1d167cf6fSWarner Losh /*- 2d63027b6SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 29681a5bbeSBoris Popov */ 30681a5bbeSBoris Popov #include <sys/param.h> 31681a5bbeSBoris Popov #include <sys/systm.h> 32681a5bbeSBoris Popov #include <sys/namei.h> 33681a5bbeSBoris Popov #include <sys/kernel.h> 34681a5bbeSBoris Popov #include <sys/proc.h> 35681a5bbeSBoris Popov #include <sys/bio.h> 36681a5bbeSBoris Popov #include <sys/buf.h> 37681a5bbeSBoris Popov #include <sys/fcntl.h> 38681a5bbeSBoris Popov #include <sys/mount.h> 39681a5bbeSBoris Popov #include <sys/unistd.h> 40681a5bbeSBoris Popov #include <sys/vnode.h> 41104a9b7eSAlexander Kabaev #include <sys/limits.h> 42681a5bbeSBoris Popov #include <sys/lockf.h> 43fb8e9eadSBoris Popov #include <sys/stat.h> 44681a5bbeSBoris Popov 45681a5bbeSBoris Popov #include <vm/vm.h> 46681a5bbeSBoris Popov #include <vm/vm_extern.h> 47681a5bbeSBoris Popov 48681a5bbeSBoris Popov 49681a5bbeSBoris Popov #include <netsmb/smb.h> 50681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 51681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 52681a5bbeSBoris Popov 53681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h> 54681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h> 55681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h> 56681a5bbeSBoris Popov 57681a5bbeSBoris Popov /* 58681a5bbeSBoris Popov * Prototypes for SMBFS vnode operations 59681a5bbeSBoris Popov */ 606fde64c7SPoul-Henning Kamp static vop_create_t smbfs_create; 616fde64c7SPoul-Henning Kamp static vop_mknod_t smbfs_mknod; 626fde64c7SPoul-Henning Kamp static vop_open_t smbfs_open; 636fde64c7SPoul-Henning Kamp static vop_close_t smbfs_close; 646fde64c7SPoul-Henning Kamp static vop_access_t smbfs_access; 656fde64c7SPoul-Henning Kamp static vop_getattr_t smbfs_getattr; 666fde64c7SPoul-Henning Kamp static vop_setattr_t smbfs_setattr; 676fde64c7SPoul-Henning Kamp static vop_read_t smbfs_read; 686fde64c7SPoul-Henning Kamp static vop_write_t smbfs_write; 696fde64c7SPoul-Henning Kamp static vop_fsync_t smbfs_fsync; 706fde64c7SPoul-Henning Kamp static vop_remove_t smbfs_remove; 716fde64c7SPoul-Henning Kamp static vop_link_t smbfs_link; 726fde64c7SPoul-Henning Kamp static vop_lookup_t smbfs_lookup; 736fde64c7SPoul-Henning Kamp static vop_rename_t smbfs_rename; 746fde64c7SPoul-Henning Kamp static vop_mkdir_t smbfs_mkdir; 756fde64c7SPoul-Henning Kamp static vop_rmdir_t smbfs_rmdir; 766fde64c7SPoul-Henning Kamp static vop_symlink_t smbfs_symlink; 776fde64c7SPoul-Henning Kamp static vop_readdir_t smbfs_readdir; 786fde64c7SPoul-Henning Kamp static vop_strategy_t smbfs_strategy; 796fde64c7SPoul-Henning Kamp static vop_print_t smbfs_print; 806fde64c7SPoul-Henning Kamp static vop_pathconf_t smbfs_pathconf; 816fde64c7SPoul-Henning Kamp static vop_advlock_t smbfs_advlock; 826fde64c7SPoul-Henning Kamp static vop_getextattr_t smbfs_getextattr; 83681a5bbeSBoris Popov 84aec0fb7bSPoul-Henning Kamp struct vop_vector smbfs_vnodeops = { 85aec0fb7bSPoul-Henning Kamp .vop_default = &default_vnodeops, 8683c64397SPoul-Henning Kamp 87aec0fb7bSPoul-Henning Kamp .vop_access = smbfs_access, 88aec0fb7bSPoul-Henning Kamp .vop_advlock = smbfs_advlock, 89aec0fb7bSPoul-Henning Kamp .vop_close = smbfs_close, 90aec0fb7bSPoul-Henning Kamp .vop_create = smbfs_create, 91aec0fb7bSPoul-Henning Kamp .vop_fsync = smbfs_fsync, 92aec0fb7bSPoul-Henning Kamp .vop_getattr = smbfs_getattr, 9383c64397SPoul-Henning Kamp .vop_getextattr = smbfs_getextattr, 94aec0fb7bSPoul-Henning Kamp .vop_getpages = smbfs_getpages, 95aec0fb7bSPoul-Henning Kamp .vop_inactive = smbfs_inactive, 96aec0fb7bSPoul-Henning Kamp .vop_ioctl = smbfs_ioctl, 97aec0fb7bSPoul-Henning Kamp .vop_link = smbfs_link, 98aec0fb7bSPoul-Henning Kamp .vop_lookup = smbfs_lookup, 99aec0fb7bSPoul-Henning Kamp .vop_mkdir = smbfs_mkdir, 100aec0fb7bSPoul-Henning Kamp .vop_mknod = smbfs_mknod, 101aec0fb7bSPoul-Henning Kamp .vop_open = smbfs_open, 102aec0fb7bSPoul-Henning Kamp .vop_pathconf = smbfs_pathconf, 103aec0fb7bSPoul-Henning Kamp .vop_print = smbfs_print, 104aec0fb7bSPoul-Henning Kamp .vop_putpages = smbfs_putpages, 105aec0fb7bSPoul-Henning Kamp .vop_read = smbfs_read, 106aec0fb7bSPoul-Henning Kamp .vop_readdir = smbfs_readdir, 107aec0fb7bSPoul-Henning Kamp .vop_reclaim = smbfs_reclaim, 108aec0fb7bSPoul-Henning Kamp .vop_remove = smbfs_remove, 109aec0fb7bSPoul-Henning Kamp .vop_rename = smbfs_rename, 110aec0fb7bSPoul-Henning Kamp .vop_rmdir = smbfs_rmdir, 111aec0fb7bSPoul-Henning Kamp .vop_setattr = smbfs_setattr, 11283c64397SPoul-Henning Kamp /* .vop_setextattr = smbfs_setextattr,*/ 113aec0fb7bSPoul-Henning Kamp .vop_strategy = smbfs_strategy, 114aec0fb7bSPoul-Henning Kamp .vop_symlink = smbfs_symlink, 115aec0fb7bSPoul-Henning Kamp .vop_write = smbfs_write, 116681a5bbeSBoris Popov }; 117*6fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(smbfs_vnodeops); 118681a5bbeSBoris Popov 119681a5bbeSBoris Popov static int 120681a5bbeSBoris Popov smbfs_access(ap) 121681a5bbeSBoris Popov struct vop_access_args /* { 122681a5bbeSBoris Popov struct vnode *a_vp; 12315bc6b2bSEdward Tomasz Napierala accmode_t a_accmode; 124681a5bbeSBoris Popov struct ucred *a_cred; 125b1c996c4SBoris Popov struct thread *a_td; 126681a5bbeSBoris Popov } */ *ap; 127681a5bbeSBoris Popov { 128681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 12915bc6b2bSEdward Tomasz Napierala accmode_t accmode = ap->a_accmode; 13038356d10STim J. Robbins mode_t mpmode; 131681a5bbeSBoris Popov struct smbmount *smp = VTOSMBFS(vp); 132681a5bbeSBoris Popov 133681a5bbeSBoris Popov SMBVDEBUG("\n"); 13415bc6b2bSEdward Tomasz Napierala if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 135681a5bbeSBoris Popov switch (vp->v_type) { 136681a5bbeSBoris Popov case VREG: case VDIR: case VLNK: 137681a5bbeSBoris Popov return EROFS; 138681a5bbeSBoris Popov default: 139681a5bbeSBoris Popov break; 140681a5bbeSBoris Popov } 141681a5bbeSBoris Popov } 142d14c8441SPoul-Henning Kamp mpmode = vp->v_type == VREG ? smp->sm_file_mode : smp->sm_dir_mode; 143d14c8441SPoul-Henning Kamp return (vaccess(vp->v_type, mpmode, smp->sm_uid, 14415bc6b2bSEdward Tomasz Napierala smp->sm_gid, ap->a_accmode, ap->a_cred, NULL)); 145681a5bbeSBoris Popov } 146681a5bbeSBoris Popov 147681a5bbeSBoris Popov /* ARGSUSED */ 148681a5bbeSBoris Popov static int 149681a5bbeSBoris Popov smbfs_open(ap) 150681a5bbeSBoris Popov struct vop_open_args /* { 151681a5bbeSBoris Popov struct vnode *a_vp; 152681a5bbeSBoris Popov int a_mode; 153681a5bbeSBoris Popov struct ucred *a_cred; 154b1c996c4SBoris Popov struct thread *a_td; 155681a5bbeSBoris Popov } */ *ap; 156681a5bbeSBoris Popov { 157681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 158681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 159afe09751SDavide Italiano struct smb_cred *scred; 160681a5bbeSBoris Popov struct vattr vattr; 161681a5bbeSBoris Popov int mode = ap->a_mode; 162681a5bbeSBoris Popov int error, accmode; 163681a5bbeSBoris Popov 1642a4ad258STim J. Robbins SMBVDEBUG("%s,%d\n", np->n_name, (np->n_flag & NOPEN) != 0); 165681a5bbeSBoris Popov if (vp->v_type != VREG && vp->v_type != VDIR) { 166681a5bbeSBoris Popov SMBFSERR("open eacces vtype=%d\n", vp->v_type); 167681a5bbeSBoris Popov return EACCES; 168681a5bbeSBoris Popov } 169681a5bbeSBoris Popov if (vp->v_type == VDIR) { 1702a4ad258STim J. Robbins np->n_flag |= NOPEN; 171681a5bbeSBoris Popov return 0; 172681a5bbeSBoris Popov } 173681a5bbeSBoris Popov if (np->n_flag & NMODIFIED) { 174e50508dfSPoul-Henning Kamp if ((error = smbfs_vinvalbuf(vp, ap->a_td)) == EINTR) 175681a5bbeSBoris Popov return error; 176681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 1770359a12eSAttilio Rao error = VOP_GETATTR(vp, &vattr, ap->a_cred); 178681a5bbeSBoris Popov if (error) 179681a5bbeSBoris Popov return error; 180681a5bbeSBoris Popov np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 181681a5bbeSBoris Popov } else { 1820359a12eSAttilio Rao error = VOP_GETATTR(vp, &vattr, ap->a_cred); 183681a5bbeSBoris Popov if (error) 184681a5bbeSBoris Popov return error; 185681a5bbeSBoris Popov if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 186e50508dfSPoul-Henning Kamp error = smbfs_vinvalbuf(vp, ap->a_td); 187681a5bbeSBoris Popov if (error == EINTR) 188681a5bbeSBoris Popov return error; 189681a5bbeSBoris Popov np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 190681a5bbeSBoris Popov } 191681a5bbeSBoris Popov } 1922a4ad258STim J. Robbins if ((np->n_flag & NOPEN) != 0) 193681a5bbeSBoris Popov return 0; 19444f3878eSBoris Popov /* 19544f3878eSBoris Popov * Use DENYNONE to give unixy semantics of permitting 19644f3878eSBoris Popov * everything not forbidden by permissions. Ie denial 19744f3878eSBoris Popov * is up to server with clients/openers needing to use 19844f3878eSBoris Popov * advisory locks for further control. 19944f3878eSBoris Popov */ 20044f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 201681a5bbeSBoris Popov if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 20244f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; 203afe09751SDavide Italiano scred = smbfs_malloc_scred(); 204afe09751SDavide Italiano smb_makescred(scred, ap->a_td, ap->a_cred); 205afe09751SDavide Italiano error = smbfs_smb_open(np, accmode, scred); 206681a5bbeSBoris Popov if (error) { 207681a5bbeSBoris Popov if (mode & FWRITE) 208681a5bbeSBoris Popov return EACCES; 20944f3878eSBoris Popov else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 21044f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 211afe09751SDavide Italiano error = smbfs_smb_open(np, accmode, scred); 212681a5bbeSBoris Popov } 21344f3878eSBoris Popov } 21472b3e305SPeter Edwards if (error == 0) { 2152a4ad258STim J. Robbins np->n_flag |= NOPEN; 21672b3e305SPeter Edwards vnode_create_vobject(ap->a_vp, vattr.va_size, ap->a_td); 21772b3e305SPeter Edwards } 218681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 219afe09751SDavide Italiano smbfs_free_scred(scred); 220681a5bbeSBoris Popov return error; 221681a5bbeSBoris Popov } 222681a5bbeSBoris Popov 223681a5bbeSBoris Popov static int 224681a5bbeSBoris Popov smbfs_close(ap) 225681a5bbeSBoris Popov struct vop_close_args /* { 226681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 227681a5bbeSBoris Popov struct vnode *a_vp; 228681a5bbeSBoris Popov int a_fflag; 229681a5bbeSBoris Popov struct ucred *a_cred; 230b1c996c4SBoris Popov struct thread *a_td; 231681a5bbeSBoris Popov } */ *ap; 232681a5bbeSBoris Popov { 233681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 234b1c996c4SBoris Popov struct thread *td = ap->a_td; 235835fb616STim J. Robbins struct smbnode *np = VTOSMB(vp); 236afe09751SDavide Italiano struct smb_cred *scred; 237681a5bbeSBoris Popov 238835fb616STim J. Robbins if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 && 239835fb616STim J. Robbins np->n_dirseq != NULL) { 240afe09751SDavide Italiano scred = smbfs_malloc_scred(); 241afe09751SDavide Italiano smb_makescred(scred, td, ap->a_cred); 242afe09751SDavide Italiano smbfs_findclose(np->n_dirseq, scred); 243afe09751SDavide Italiano smbfs_free_scred(scred); 244835fb616STim J. Robbins np->n_dirseq = NULL; 245835fb616STim J. Robbins } 2462a4ad258STim J. Robbins return 0; 247681a5bbeSBoris Popov } 248681a5bbeSBoris Popov 249681a5bbeSBoris Popov /* 250681a5bbeSBoris Popov * smbfs_getattr call from vfs. 251681a5bbeSBoris Popov */ 252681a5bbeSBoris Popov static int 253681a5bbeSBoris Popov smbfs_getattr(ap) 254681a5bbeSBoris Popov struct vop_getattr_args /* { 255681a5bbeSBoris Popov struct vnode *a_vp; 256681a5bbeSBoris Popov struct vattr *a_vap; 257681a5bbeSBoris Popov struct ucred *a_cred; 258681a5bbeSBoris Popov } */ *ap; 259681a5bbeSBoris Popov { 260681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 261681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 262681a5bbeSBoris Popov struct vattr *va=ap->a_vap; 263681a5bbeSBoris Popov struct smbfattr fattr; 264afe09751SDavide Italiano struct smb_cred *scred; 26507a65634STim J. Robbins u_quad_t oldsize; 266681a5bbeSBoris Popov int error; 267681a5bbeSBoris Popov 268e6e370a7SJeff Roberson SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 269681a5bbeSBoris Popov error = smbfs_attr_cachelookup(vp, va); 270681a5bbeSBoris Popov if (!error) 271681a5bbeSBoris Popov return 0; 272681a5bbeSBoris Popov SMBVDEBUG("not in the cache\n"); 273afe09751SDavide Italiano scred = smbfs_malloc_scred(); 274afe09751SDavide Italiano smb_makescred(scred, curthread, ap->a_cred); 275681a5bbeSBoris Popov oldsize = np->n_size; 276afe09751SDavide Italiano error = smbfs_smb_lookup(np, NULL, 0, &fattr, scred); 277681a5bbeSBoris Popov if (error) { 278681a5bbeSBoris Popov SMBVDEBUG("error %d\n", error); 279afe09751SDavide Italiano smbfs_free_scred(scred); 280681a5bbeSBoris Popov return error; 281681a5bbeSBoris Popov } 282681a5bbeSBoris Popov smbfs_attr_cacheenter(vp, &fattr); 283681a5bbeSBoris Popov smbfs_attr_cachelookup(vp, va); 2842a4ad258STim J. Robbins if (np->n_flag & NOPEN) 285681a5bbeSBoris Popov np->n_size = oldsize; 286afe09751SDavide Italiano smbfs_free_scred(scred); 287681a5bbeSBoris Popov return 0; 288681a5bbeSBoris Popov } 289681a5bbeSBoris Popov 290681a5bbeSBoris Popov static int 291681a5bbeSBoris Popov smbfs_setattr(ap) 292681a5bbeSBoris Popov struct vop_setattr_args /* { 293681a5bbeSBoris Popov struct vnode *a_vp; 294681a5bbeSBoris Popov struct vattr *a_vap; 295681a5bbeSBoris Popov struct ucred *a_cred; 296681a5bbeSBoris Popov } */ *ap; 297681a5bbeSBoris Popov { 298681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 299681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 300681a5bbeSBoris Popov struct vattr *vap = ap->a_vap; 301681a5bbeSBoris Popov struct timespec *mtime, *atime; 302afe09751SDavide Italiano struct smb_cred *scred; 303681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 304681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ssp); 3050359a12eSAttilio Rao struct thread *td = curthread; 306681a5bbeSBoris Popov u_quad_t tsize = 0; 307681a5bbeSBoris Popov int isreadonly, doclose, error = 0; 308fb8e9eadSBoris Popov int old_n_dosattr; 309681a5bbeSBoris Popov 310681a5bbeSBoris Popov SMBVDEBUG("\n"); 311681a5bbeSBoris Popov isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 312681a5bbeSBoris Popov /* 313681a5bbeSBoris Popov * Disallow write attempts if the filesystem is mounted read-only. 314681a5bbeSBoris Popov */ 315681a5bbeSBoris Popov if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 316681a5bbeSBoris Popov vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 3177da1a731SKenneth D. Merry vap->va_mode != (mode_t)VNOVAL || vap->va_flags != VNOVAL) && 3187da1a731SKenneth D. Merry isreadonly) 319681a5bbeSBoris Popov return EROFS; 3207da1a731SKenneth D. Merry 3217da1a731SKenneth D. Merry /* 3227da1a731SKenneth D. Merry * We only support setting four flags. Don't allow setting others. 3237da1a731SKenneth D. Merry * 3247da1a731SKenneth D. Merry * We map UF_READONLY to SMB_FA_RDONLY, unlike the MacOS X version 3257da1a731SKenneth D. Merry * of this code, which maps both UF_IMMUTABLE AND SF_IMMUTABLE to 3267da1a731SKenneth D. Merry * SMB_FA_RDONLY. The immutable flags have different semantics 3277da1a731SKenneth D. Merry * than readonly, which is the reason for the difference. 3287da1a731SKenneth D. Merry */ 3297da1a731SKenneth D. Merry if (vap->va_flags != VNOVAL) { 3307da1a731SKenneth D. Merry if (vap->va_flags & ~(UF_HIDDEN|UF_SYSTEM|UF_ARCHIVE| 3317da1a731SKenneth D. Merry UF_READONLY)) 3327da1a731SKenneth D. Merry return EINVAL; 3337da1a731SKenneth D. Merry } 3347da1a731SKenneth D. Merry 335afe09751SDavide Italiano scred = smbfs_malloc_scred(); 336afe09751SDavide Italiano smb_makescred(scred, td, ap->a_cred); 337681a5bbeSBoris Popov if (vap->va_size != VNOVAL) { 338681a5bbeSBoris Popov switch (vp->v_type) { 339681a5bbeSBoris Popov case VDIR: 340afe09751SDavide Italiano error = EISDIR; 341afe09751SDavide Italiano goto out; 342681a5bbeSBoris Popov case VREG: 343681a5bbeSBoris Popov break; 344681a5bbeSBoris Popov default: 345afe09751SDavide Italiano error = EINVAL; 346afe09751SDavide Italiano goto out; 34774b8d63dSPedro F. Giffuni } 348afe09751SDavide Italiano if (isreadonly) { 349afe09751SDavide Italiano error = EROFS; 350afe09751SDavide Italiano goto out; 351afe09751SDavide Italiano } 352681a5bbeSBoris Popov doclose = 0; 353681a5bbeSBoris Popov vnode_pager_setsize(vp, (u_long)vap->va_size); 354681a5bbeSBoris Popov tsize = np->n_size; 355681a5bbeSBoris Popov np->n_size = vap->va_size; 3562a4ad258STim J. Robbins if ((np->n_flag & NOPEN) == 0) { 35744f3878eSBoris Popov error = smbfs_smb_open(np, 35844f3878eSBoris Popov SMB_SM_DENYNONE|SMB_AM_OPENRW, 359afe09751SDavide Italiano scred); 360681a5bbeSBoris Popov if (error == 0) 361681a5bbeSBoris Popov doclose = 1; 362681a5bbeSBoris Popov } 363681a5bbeSBoris Popov if (error == 0) 364c829016eSAndrey V. Elsukov error = smbfs_smb_setfsize(np, 365c829016eSAndrey V. Elsukov (int64_t)vap->va_size, scred); 366681a5bbeSBoris Popov if (doclose) 367afe09751SDavide Italiano smbfs_smb_close(ssp, np->n_fid, NULL, scred); 368681a5bbeSBoris Popov if (error) { 369681a5bbeSBoris Popov np->n_size = tsize; 370681a5bbeSBoris Popov vnode_pager_setsize(vp, (u_long)tsize); 371afe09751SDavide Italiano goto out; 372681a5bbeSBoris Popov } 373681a5bbeSBoris Popov } 3747da1a731SKenneth D. Merry if ((vap->va_flags != VNOVAL) || (vap->va_mode != (mode_t)VNOVAL)) { 375fb8e9eadSBoris Popov old_n_dosattr = np->n_dosattr; 3767da1a731SKenneth D. Merry 3777da1a731SKenneth D. Merry if (vap->va_mode != (mode_t)VNOVAL) { 378fb8e9eadSBoris Popov if (vap->va_mode & S_IWUSR) 379fb8e9eadSBoris Popov np->n_dosattr &= ~SMB_FA_RDONLY; 380fb8e9eadSBoris Popov else 381fb8e9eadSBoris Popov np->n_dosattr |= SMB_FA_RDONLY; 3827da1a731SKenneth D. Merry } 3837da1a731SKenneth D. Merry 3847da1a731SKenneth D. Merry if (vap->va_flags != VNOVAL) { 3857da1a731SKenneth D. Merry if (vap->va_flags & UF_HIDDEN) 3867da1a731SKenneth D. Merry np->n_dosattr |= SMB_FA_HIDDEN; 3877da1a731SKenneth D. Merry else 3887da1a731SKenneth D. Merry np->n_dosattr &= ~SMB_FA_HIDDEN; 3897da1a731SKenneth D. Merry 3907da1a731SKenneth D. Merry if (vap->va_flags & UF_SYSTEM) 3917da1a731SKenneth D. Merry np->n_dosattr |= SMB_FA_SYSTEM; 3927da1a731SKenneth D. Merry else 3937da1a731SKenneth D. Merry np->n_dosattr &= ~SMB_FA_SYSTEM; 3947da1a731SKenneth D. Merry 3957da1a731SKenneth D. Merry if (vap->va_flags & UF_ARCHIVE) 3967da1a731SKenneth D. Merry np->n_dosattr |= SMB_FA_ARCHIVE; 3977da1a731SKenneth D. Merry else 3987da1a731SKenneth D. Merry np->n_dosattr &= ~SMB_FA_ARCHIVE; 3997da1a731SKenneth D. Merry 4007da1a731SKenneth D. Merry /* 4017da1a731SKenneth D. Merry * We only support setting the immutable / readonly 4027da1a731SKenneth D. Merry * bit for regular files. According to comments in 4037da1a731SKenneth D. Merry * the MacOS X version of this code, supporting the 4047da1a731SKenneth D. Merry * readonly bit on directories doesn't do the same 4057da1a731SKenneth D. Merry * thing in Windows as in Unix. 4067da1a731SKenneth D. Merry */ 4077da1a731SKenneth D. Merry if (vp->v_type == VREG) { 4087da1a731SKenneth D. Merry if (vap->va_flags & UF_READONLY) 4097da1a731SKenneth D. Merry np->n_dosattr |= SMB_FA_RDONLY; 4107da1a731SKenneth D. Merry else 4117da1a731SKenneth D. Merry np->n_dosattr &= ~SMB_FA_RDONLY; 4127da1a731SKenneth D. Merry } 4137da1a731SKenneth D. Merry } 4147da1a731SKenneth D. Merry 415fb8e9eadSBoris Popov if (np->n_dosattr != old_n_dosattr) { 416afe09751SDavide Italiano error = smbfs_smb_setpattr(np, np->n_dosattr, NULL, scred); 417fb8e9eadSBoris Popov if (error) 418afe09751SDavide Italiano goto out; 419fb8e9eadSBoris Popov } 420fb8e9eadSBoris Popov } 421681a5bbeSBoris Popov mtime = atime = NULL; 422681a5bbeSBoris Popov if (vap->va_mtime.tv_sec != VNOVAL) 423681a5bbeSBoris Popov mtime = &vap->va_mtime; 424681a5bbeSBoris Popov if (vap->va_atime.tv_sec != VNOVAL) 425681a5bbeSBoris Popov atime = &vap->va_atime; 426681a5bbeSBoris Popov if (mtime != atime) { 427acd3428bSRobert Watson if (vap->va_vaflags & VA_UTIMES_NULL) { 4280359a12eSAttilio Rao error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 429acd3428bSRobert Watson if (error) 4300359a12eSAttilio Rao error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td); 431acd3428bSRobert Watson } else 4320359a12eSAttilio Rao error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 433681a5bbeSBoris Popov #if 0 434681a5bbeSBoris Popov if (mtime == NULL) 435681a5bbeSBoris Popov mtime = &np->n_mtime; 436681a5bbeSBoris Popov if (atime == NULL) 437681a5bbeSBoris Popov atime = &np->n_atime; 438681a5bbeSBoris Popov #endif 439681a5bbeSBoris Popov /* 440681a5bbeSBoris Popov * If file is opened, then we can use handle based calls. 441681a5bbeSBoris Popov * If not, use path based ones. 442681a5bbeSBoris Popov */ 4432a4ad258STim J. Robbins if ((np->n_flag & NOPEN) == 0) { 444681a5bbeSBoris Popov if (vcp->vc_flags & SMBV_WIN95) { 4450359a12eSAttilio Rao error = VOP_OPEN(vp, FWRITE, ap->a_cred, td, 4460359a12eSAttilio Rao NULL); 447681a5bbeSBoris Popov if (!error) { 4480359a12eSAttilio Rao /* error = smbfs_smb_setfattrNT(np, 0, 449afe09751SDavide Italiano mtime, atime, scred); 4500359a12eSAttilio Rao VOP_GETATTR(vp, &vattr, ap->a_cred); */ 451681a5bbeSBoris Popov if (mtime) 452681a5bbeSBoris Popov np->n_mtime = *mtime; 4530359a12eSAttilio Rao VOP_CLOSE(vp, FWRITE, ap->a_cred, td); 454681a5bbeSBoris Popov } 455681a5bbeSBoris Popov } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 456afe09751SDavide Italiano error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); 457afe09751SDavide Italiano /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, scred);*/ 458681a5bbeSBoris Popov } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 459afe09751SDavide Italiano error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); 460681a5bbeSBoris Popov } else { 461afe09751SDavide Italiano error = smbfs_smb_setpattr(np, 0, mtime, scred); 462681a5bbeSBoris Popov } 463681a5bbeSBoris Popov } else { 464681a5bbeSBoris Popov if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 465afe09751SDavide Italiano error = smbfs_smb_setfattrNT(np, 0, mtime, atime, scred); 466681a5bbeSBoris Popov } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 467afe09751SDavide Italiano error = smbfs_smb_setftime(np, mtime, atime, scred); 468681a5bbeSBoris Popov } else { 469681a5bbeSBoris Popov /* 470681a5bbeSBoris Popov * I have no idea how to handle this for core 471681a5bbeSBoris Popov * level servers. The possible solution is to 472681a5bbeSBoris Popov * update mtime after file is closed. 473681a5bbeSBoris Popov */ 474681a5bbeSBoris Popov SMBERROR("can't update times on an opened file\n"); 475681a5bbeSBoris Popov } 476681a5bbeSBoris Popov } 477681a5bbeSBoris Popov } 478681a5bbeSBoris Popov /* 479681a5bbeSBoris Popov * Invalidate attribute cache in case if server doesn't set 480681a5bbeSBoris Popov * required attributes. 481681a5bbeSBoris Popov */ 482681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); /* invalidate cache */ 4830359a12eSAttilio Rao VOP_GETATTR(vp, vap, ap->a_cred); 484681a5bbeSBoris Popov np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 485afe09751SDavide Italiano out: 486afe09751SDavide Italiano smbfs_free_scred(scred); 487681a5bbeSBoris Popov return error; 488681a5bbeSBoris Popov } 489681a5bbeSBoris Popov /* 490681a5bbeSBoris Popov * smbfs_read call. 491681a5bbeSBoris Popov */ 492681a5bbeSBoris Popov static int 493681a5bbeSBoris Popov smbfs_read(ap) 494681a5bbeSBoris Popov struct vop_read_args /* { 495681a5bbeSBoris Popov struct vnode *a_vp; 496681a5bbeSBoris Popov struct uio *a_uio; 497681a5bbeSBoris Popov int a_ioflag; 498681a5bbeSBoris Popov struct ucred *a_cred; 499681a5bbeSBoris Popov } */ *ap; 500681a5bbeSBoris Popov { 501681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 502681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 503681a5bbeSBoris Popov 504681a5bbeSBoris Popov SMBVDEBUG("\n"); 505681a5bbeSBoris Popov if (vp->v_type != VREG && vp->v_type != VDIR) 506681a5bbeSBoris Popov return EPERM; 507681a5bbeSBoris Popov return smbfs_readvnode(vp, uio, ap->a_cred); 508681a5bbeSBoris Popov } 509681a5bbeSBoris Popov 510681a5bbeSBoris Popov static int 511681a5bbeSBoris Popov smbfs_write(ap) 512681a5bbeSBoris Popov struct vop_write_args /* { 513681a5bbeSBoris Popov struct vnode *a_vp; 514681a5bbeSBoris Popov struct uio *a_uio; 515681a5bbeSBoris Popov int a_ioflag; 516681a5bbeSBoris Popov struct ucred *a_cred; 517681a5bbeSBoris Popov } */ *ap; 518681a5bbeSBoris Popov { 519681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 520681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 521681a5bbeSBoris Popov 522994f027fSDavide Italiano SMBVDEBUG("%d,ofs=%jd,sz=%zd\n",vp->v_type, (intmax_t)uio->uio_offset, 523469cb18fSDavide Italiano uio->uio_resid); 524681a5bbeSBoris Popov if (vp->v_type != VREG) 525681a5bbeSBoris Popov return (EPERM); 526681a5bbeSBoris Popov return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 527681a5bbeSBoris Popov } 528681a5bbeSBoris Popov /* 529681a5bbeSBoris Popov * smbfs_create call 530681a5bbeSBoris Popov * Create a regular file. On entry the directory to contain the file being 531681a5bbeSBoris Popov * created is locked. We must release before we return. We must also free 532681a5bbeSBoris Popov * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 533681a5bbeSBoris Popov * only if the SAVESTART bit in cn_flags is clear on success. 534681a5bbeSBoris Popov */ 535681a5bbeSBoris Popov static int 536681a5bbeSBoris Popov smbfs_create(ap) 537681a5bbeSBoris Popov struct vop_create_args /* { 538681a5bbeSBoris Popov struct vnode *a_dvp; 539681a5bbeSBoris Popov struct vnode **a_vpp; 540681a5bbeSBoris Popov struct componentname *a_cnp; 541681a5bbeSBoris Popov struct vattr *a_vap; 542681a5bbeSBoris Popov } */ *ap; 543681a5bbeSBoris Popov { 544681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 545681a5bbeSBoris Popov struct vattr *vap = ap->a_vap; 546681a5bbeSBoris Popov struct vnode **vpp=ap->a_vpp; 547681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 548681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 549681a5bbeSBoris Popov struct vnode *vp; 550681a5bbeSBoris Popov struct vattr vattr; 551681a5bbeSBoris Popov struct smbfattr fattr; 552afe09751SDavide Italiano struct smb_cred *scred; 553681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 554681a5bbeSBoris Popov int nmlen = cnp->cn_namelen; 555681a5bbeSBoris Popov int error; 556681a5bbeSBoris Popov 557681a5bbeSBoris Popov 558681a5bbeSBoris Popov SMBVDEBUG("\n"); 559681a5bbeSBoris Popov *vpp = NULL; 560681a5bbeSBoris Popov if (vap->va_type != VREG) 561681a5bbeSBoris Popov return EOPNOTSUPP; 5620359a12eSAttilio Rao if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 563681a5bbeSBoris Popov return error; 564afe09751SDavide Italiano scred = smbfs_malloc_scred(); 565afe09751SDavide Italiano smb_makescred(scred, cnp->cn_thread, cnp->cn_cred); 566681a5bbeSBoris Popov 567afe09751SDavide Italiano error = smbfs_smb_create(dnp, name, nmlen, scred); 568681a5bbeSBoris Popov if (error) 569afe09751SDavide Italiano goto out; 570afe09751SDavide Italiano error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, scred); 571681a5bbeSBoris Popov if (error) 572afe09751SDavide Italiano goto out; 573681a5bbeSBoris Popov error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 574681a5bbeSBoris Popov if (error) 575afe09751SDavide Italiano goto out; 576681a5bbeSBoris Popov *vpp = vp; 577681a5bbeSBoris Popov if (cnp->cn_flags & MAKEENTRY) 578681a5bbeSBoris Popov cache_enter(dvp, vp, cnp); 579afe09751SDavide Italiano out: 580afe09751SDavide Italiano smbfs_free_scred(scred); 581681a5bbeSBoris Popov return error; 582681a5bbeSBoris Popov } 583681a5bbeSBoris Popov 584681a5bbeSBoris Popov static int 585681a5bbeSBoris Popov smbfs_remove(ap) 586681a5bbeSBoris Popov struct vop_remove_args /* { 587681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 588681a5bbeSBoris Popov struct vnode * a_dvp; 589681a5bbeSBoris Popov struct vnode * a_vp; 590681a5bbeSBoris Popov struct componentname * a_cnp; 591681a5bbeSBoris Popov } */ *ap; 592681a5bbeSBoris Popov { 593681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 594681a5bbeSBoris Popov /* struct vnode *dvp = ap->a_dvp;*/ 595681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 596681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 597afe09751SDavide Italiano struct smb_cred *scred; 598681a5bbeSBoris Popov int error; 599681a5bbeSBoris Popov 6002a4ad258STim J. Robbins if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) 601681a5bbeSBoris Popov return EPERM; 602afe09751SDavide Italiano scred = smbfs_malloc_scred(); 603afe09751SDavide Italiano smb_makescred(scred, cnp->cn_thread, cnp->cn_cred); 604afe09751SDavide Italiano error = smbfs_smb_delete(np, scred); 605b4484bf0STim J. Robbins if (error == 0) 606b4484bf0STim J. Robbins np->n_flag |= NGONE; 607681a5bbeSBoris Popov cache_purge(vp); 608afe09751SDavide Italiano smbfs_free_scred(scred); 609681a5bbeSBoris Popov return error; 610681a5bbeSBoris Popov } 611681a5bbeSBoris Popov 612681a5bbeSBoris Popov /* 613681a5bbeSBoris Popov * smbfs_file rename call 614681a5bbeSBoris Popov */ 615681a5bbeSBoris Popov static int 616681a5bbeSBoris Popov smbfs_rename(ap) 617681a5bbeSBoris Popov struct vop_rename_args /* { 618681a5bbeSBoris Popov struct vnode *a_fdvp; 619681a5bbeSBoris Popov struct vnode *a_fvp; 620681a5bbeSBoris Popov struct componentname *a_fcnp; 621681a5bbeSBoris Popov struct vnode *a_tdvp; 622681a5bbeSBoris Popov struct vnode *a_tvp; 623681a5bbeSBoris Popov struct componentname *a_tcnp; 624681a5bbeSBoris Popov } */ *ap; 625681a5bbeSBoris Popov { 626681a5bbeSBoris Popov struct vnode *fvp = ap->a_fvp; 627681a5bbeSBoris Popov struct vnode *tvp = ap->a_tvp; 628681a5bbeSBoris Popov struct vnode *fdvp = ap->a_fdvp; 629681a5bbeSBoris Popov struct vnode *tdvp = ap->a_tdvp; 630681a5bbeSBoris Popov struct componentname *tcnp = ap->a_tcnp; 631681a5bbeSBoris Popov /* struct componentname *fcnp = ap->a_fcnp;*/ 632afe09751SDavide Italiano struct smb_cred *scred; 633681a5bbeSBoris Popov u_int16_t flags = 6; 634681a5bbeSBoris Popov int error=0; 635681a5bbeSBoris Popov 636e346bd81SDavide Italiano scred = NULL; 637681a5bbeSBoris Popov /* Check for cross-device rename */ 638681a5bbeSBoris Popov if ((fvp->v_mount != tdvp->v_mount) || 639681a5bbeSBoris Popov (tvp && (fvp->v_mount != tvp->v_mount))) { 64042039c5bSDavide Italiano error = EXDEV; 641681a5bbeSBoris Popov goto out; 642681a5bbeSBoris Popov } 643681a5bbeSBoris Popov 6444d93c0beSJeff Roberson if (tvp && vrefcnt(tvp) > 1) { 64542039c5bSDavide Italiano error = EBUSY; 646681a5bbeSBoris Popov goto out; 647681a5bbeSBoris Popov } 648681a5bbeSBoris Popov flags = 0x10; /* verify all writes */ 649681a5bbeSBoris Popov if (fvp->v_type == VDIR) { 650681a5bbeSBoris Popov flags |= 2; 651681a5bbeSBoris Popov } else if (fvp->v_type == VREG) { 652681a5bbeSBoris Popov flags |= 1; 6536dae0c1eSTim J. Robbins } else { 654afe09751SDavide Italiano return EINVAL; 6556dae0c1eSTim J. Robbins } 656afe09751SDavide Italiano scred = smbfs_malloc_scred(); 657afe09751SDavide Italiano smb_makescred(scred, tcnp->cn_thread, tcnp->cn_cred); 658681a5bbeSBoris Popov /* 659681a5bbeSBoris Popov * It seems that Samba doesn't implement SMB_COM_MOVE call... 660681a5bbeSBoris Popov */ 661681a5bbeSBoris Popov #ifdef notnow 662681a5bbeSBoris Popov if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 663681a5bbeSBoris Popov error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 664afe09751SDavide Italiano tcnp->cn_nameptr, tcnp->cn_namelen, flags, scred); 665681a5bbeSBoris Popov } else 666681a5bbeSBoris Popov #endif 667681a5bbeSBoris Popov { 668681a5bbeSBoris Popov /* 669681a5bbeSBoris Popov * We have to do the work atomicaly 670681a5bbeSBoris Popov */ 671681a5bbeSBoris Popov if (tvp && tvp != fvp) { 672afe09751SDavide Italiano error = smbfs_smb_delete(VTOSMB(tvp), scred); 673681a5bbeSBoris Popov if (error) 6746dae0c1eSTim J. Robbins goto out_cacherem; 675b4484bf0STim J. Robbins VTOSMB(fvp)->n_flag |= NGONE; 676681a5bbeSBoris Popov } 677681a5bbeSBoris Popov error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 678afe09751SDavide Italiano tcnp->cn_nameptr, tcnp->cn_namelen, scred); 679681a5bbeSBoris Popov } 680681a5bbeSBoris Popov 681681a5bbeSBoris Popov if (fvp->v_type == VDIR) { 682681a5bbeSBoris Popov if (tvp != NULL && tvp->v_type == VDIR) 683681a5bbeSBoris Popov cache_purge(tdvp); 684681a5bbeSBoris Popov cache_purge(fdvp); 685681a5bbeSBoris Popov } 6866dae0c1eSTim J. Robbins 6876dae0c1eSTim J. Robbins out_cacherem: 6886dae0c1eSTim J. Robbins smbfs_attr_cacheremove(fdvp); 6896dae0c1eSTim J. Robbins smbfs_attr_cacheremove(tdvp); 690681a5bbeSBoris Popov out: 691afe09751SDavide Italiano smbfs_free_scred(scred); 692681a5bbeSBoris Popov if (tdvp == tvp) 693681a5bbeSBoris Popov vrele(tdvp); 694681a5bbeSBoris Popov else 695681a5bbeSBoris Popov vput(tdvp); 696681a5bbeSBoris Popov if (tvp) 697681a5bbeSBoris Popov vput(tvp); 698681a5bbeSBoris Popov vrele(fdvp); 699681a5bbeSBoris Popov vrele(fvp); 700681a5bbeSBoris Popov #ifdef possible_mistake 701681a5bbeSBoris Popov vgone(fvp); 702681a5bbeSBoris Popov if (tvp) 703681a5bbeSBoris Popov vgone(tvp); 704681a5bbeSBoris Popov #endif 705681a5bbeSBoris Popov return error; 706681a5bbeSBoris Popov } 707681a5bbeSBoris Popov 7088e67c454STim J. Robbins /* 7098e67c454STim J. Robbins * somtime it will come true... 7108e67c454STim J. Robbins */ 7118e67c454STim J. Robbins static int 7128e67c454STim J. Robbins smbfs_link(ap) 7138e67c454STim J. Robbins struct vop_link_args /* { 7148e67c454STim J. Robbins struct vnode *a_tdvp; 7158e67c454STim J. Robbins struct vnode *a_vp; 7168e67c454STim J. Robbins struct componentname *a_cnp; 7178e67c454STim J. Robbins } */ *ap; 7188e67c454STim J. Robbins { 7198e67c454STim J. Robbins return EOPNOTSUPP; 7208e67c454STim J. Robbins } 7218e67c454STim J. Robbins 7228e67c454STim J. Robbins /* 7238e67c454STim J. Robbins * smbfs_symlink link create call. 7248e67c454STim J. Robbins * Sometime it will be functional... 7258e67c454STim J. Robbins */ 7268e67c454STim J. Robbins static int 7278e67c454STim J. Robbins smbfs_symlink(ap) 7288e67c454STim J. Robbins struct vop_symlink_args /* { 7298e67c454STim J. Robbins struct vnode *a_dvp; 7308e67c454STim J. Robbins struct vnode **a_vpp; 7318e67c454STim J. Robbins struct componentname *a_cnp; 7328e67c454STim J. Robbins struct vattr *a_vap; 7338e67c454STim J. Robbins char *a_target; 7348e67c454STim J. Robbins } */ *ap; 7358e67c454STim J. Robbins { 7368e67c454STim J. Robbins return EOPNOTSUPP; 7378e67c454STim J. Robbins } 7388e67c454STim J. Robbins 7398e67c454STim J. Robbins static int 7408e67c454STim J. Robbins smbfs_mknod(ap) 7418e67c454STim J. Robbins struct vop_mknod_args /* { 7428e67c454STim J. Robbins } */ *ap; 7438e67c454STim J. Robbins { 7448e67c454STim J. Robbins return EOPNOTSUPP; 7458e67c454STim J. Robbins } 7468e67c454STim J. Robbins 747681a5bbeSBoris Popov static int 748681a5bbeSBoris Popov smbfs_mkdir(ap) 749681a5bbeSBoris Popov struct vop_mkdir_args /* { 750681a5bbeSBoris Popov struct vnode *a_dvp; 751681a5bbeSBoris Popov struct vnode **a_vpp; 752681a5bbeSBoris Popov struct componentname *a_cnp; 753681a5bbeSBoris Popov struct vattr *a_vap; 754681a5bbeSBoris Popov } */ *ap; 755681a5bbeSBoris Popov { 756681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 757681a5bbeSBoris Popov /* struct vattr *vap = ap->a_vap;*/ 758681a5bbeSBoris Popov struct vnode *vp; 759681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 760681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 761681a5bbeSBoris Popov struct vattr vattr; 762afe09751SDavide Italiano struct smb_cred *scred; 763681a5bbeSBoris Popov struct smbfattr fattr; 764681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 765681a5bbeSBoris Popov int len = cnp->cn_namelen; 766681a5bbeSBoris Popov int error; 767681a5bbeSBoris Popov 7680359a12eSAttilio Rao if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) { 769681a5bbeSBoris Popov return error; 770681a5bbeSBoris Popov } 771681a5bbeSBoris Popov if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 772681a5bbeSBoris Popov return EEXIST; 773afe09751SDavide Italiano scred = smbfs_malloc_scred(); 774afe09751SDavide Italiano smb_makescred(scred, cnp->cn_thread, cnp->cn_cred); 775afe09751SDavide Italiano error = smbfs_smb_mkdir(dnp, name, len, scred); 776681a5bbeSBoris Popov if (error) 777afe09751SDavide Italiano goto out; 778afe09751SDavide Italiano error = smbfs_smb_lookup(dnp, name, len, &fattr, scred); 779681a5bbeSBoris Popov if (error) 780afe09751SDavide Italiano goto out; 781681a5bbeSBoris Popov error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 782681a5bbeSBoris Popov if (error) 783afe09751SDavide Italiano goto out; 784681a5bbeSBoris Popov *ap->a_vpp = vp; 785afe09751SDavide Italiano out: 786afe09751SDavide Italiano smbfs_free_scred(scred); 787e346bd81SDavide Italiano return error; 788681a5bbeSBoris Popov } 789681a5bbeSBoris Popov 790681a5bbeSBoris Popov /* 791681a5bbeSBoris Popov * smbfs_remove directory call 792681a5bbeSBoris Popov */ 793681a5bbeSBoris Popov static int 794681a5bbeSBoris Popov smbfs_rmdir(ap) 795681a5bbeSBoris Popov struct vop_rmdir_args /* { 796681a5bbeSBoris Popov struct vnode *a_dvp; 797681a5bbeSBoris Popov struct vnode *a_vp; 798681a5bbeSBoris Popov struct componentname *a_cnp; 799681a5bbeSBoris Popov } */ *ap; 800681a5bbeSBoris Popov { 801681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 802681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 803681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 804681a5bbeSBoris Popov /* struct smbmount *smp = VTOSMBFS(vp);*/ 805681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 806681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 807afe09751SDavide Italiano struct smb_cred *scred; 808681a5bbeSBoris Popov int error; 809681a5bbeSBoris Popov 810681a5bbeSBoris Popov if (dvp == vp) 811681a5bbeSBoris Popov return EINVAL; 812681a5bbeSBoris Popov 813afe09751SDavide Italiano scred = smbfs_malloc_scred(); 814afe09751SDavide Italiano smb_makescred(scred, cnp->cn_thread, cnp->cn_cred); 815afe09751SDavide Italiano error = smbfs_smb_rmdir(np, scred); 816b4484bf0STim J. Robbins if (error == 0) 817b4484bf0STim J. Robbins np->n_flag |= NGONE; 818681a5bbeSBoris Popov dnp->n_flag |= NMODIFIED; 819681a5bbeSBoris Popov smbfs_attr_cacheremove(dvp); 820681a5bbeSBoris Popov /* cache_purge(dvp);*/ 821681a5bbeSBoris Popov cache_purge(vp); 822afe09751SDavide Italiano smbfs_free_scred(scred); 823681a5bbeSBoris Popov return error; 824681a5bbeSBoris Popov } 825681a5bbeSBoris Popov 826681a5bbeSBoris Popov /* 827681a5bbeSBoris Popov * smbfs_readdir call 828681a5bbeSBoris Popov */ 829681a5bbeSBoris Popov static int 830681a5bbeSBoris Popov smbfs_readdir(ap) 831681a5bbeSBoris Popov struct vop_readdir_args /* { 832681a5bbeSBoris Popov struct vnode *a_vp; 833681a5bbeSBoris Popov struct uio *a_uio; 834681a5bbeSBoris Popov struct ucred *a_cred; 835681a5bbeSBoris Popov int *a_eofflag; 836681a5bbeSBoris Popov u_long *a_cookies; 837681a5bbeSBoris Popov int a_ncookies; 838681a5bbeSBoris Popov } */ *ap; 839681a5bbeSBoris Popov { 840681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 841681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 842681a5bbeSBoris Popov int error; 843681a5bbeSBoris Popov 844681a5bbeSBoris Popov if (vp->v_type != VDIR) 845681a5bbeSBoris Popov return (EPERM); 846681a5bbeSBoris Popov #ifdef notnow 847681a5bbeSBoris Popov if (ap->a_ncookies) { 848681a5bbeSBoris Popov printf("smbfs_readdir: no support for cookies now..."); 849681a5bbeSBoris Popov return (EOPNOTSUPP); 850681a5bbeSBoris Popov } 851681a5bbeSBoris Popov #endif 852681a5bbeSBoris Popov error = smbfs_readvnode(vp, uio, ap->a_cred); 853681a5bbeSBoris Popov return error; 854681a5bbeSBoris Popov } 855681a5bbeSBoris Popov 856681a5bbeSBoris Popov /* ARGSUSED */ 857681a5bbeSBoris Popov static int 858681a5bbeSBoris Popov smbfs_fsync(ap) 859681a5bbeSBoris Popov struct vop_fsync_args /* { 860681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 861681a5bbeSBoris Popov struct vnode * a_vp; 862681a5bbeSBoris Popov struct ucred * a_cred; 863681a5bbeSBoris Popov int a_waitfor; 864b1c996c4SBoris Popov struct thread * a_td; 865681a5bbeSBoris Popov } */ *ap; 866681a5bbeSBoris Popov { 867b1c996c4SBoris Popov /* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 868681a5bbeSBoris Popov return (0); 869681a5bbeSBoris Popov } 870681a5bbeSBoris Popov 871681a5bbeSBoris Popov static 872681a5bbeSBoris Popov int smbfs_print (ap) 873681a5bbeSBoris Popov struct vop_print_args /* { 874681a5bbeSBoris Popov struct vnode *a_vp; 875681a5bbeSBoris Popov } */ *ap; 876681a5bbeSBoris Popov { 877681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 878681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 879681a5bbeSBoris Popov 880681a5bbeSBoris Popov if (np == NULL) { 881681a5bbeSBoris Popov printf("no smbnode data\n"); 882681a5bbeSBoris Popov return (0); 883681a5bbeSBoris Popov } 8842a4ad258STim J. Robbins printf("\tname = %s, parent = %p, open = %d\n", np->n_name, 8852a4ad258STim J. Robbins np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); 886681a5bbeSBoris Popov return (0); 887681a5bbeSBoris Popov } 888681a5bbeSBoris Popov 889681a5bbeSBoris Popov static int 890681a5bbeSBoris Popov smbfs_pathconf (ap) 891681a5bbeSBoris Popov struct vop_pathconf_args /* { 892681a5bbeSBoris Popov struct vnode *vp; 893681a5bbeSBoris Popov int name; 894681a5bbeSBoris Popov register_t *retval; 895681a5bbeSBoris Popov } */ *ap; 896681a5bbeSBoris Popov { 897681a5bbeSBoris Popov struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 898681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(smp->sm_share); 899b1288166SJohn Baldwin long *retval = ap->a_retval; 900681a5bbeSBoris Popov int error = 0; 901681a5bbeSBoris Popov 902681a5bbeSBoris Popov switch (ap->a_name) { 9034a627952SJohn Baldwin case _PC_FILESIZEBITS: 9044a627952SJohn Baldwin if (vcp->vc_sopt.sv_caps & (SMB_CAP_LARGE_READX | 9054a627952SJohn Baldwin SMB_CAP_LARGE_WRITEX)) 9064a627952SJohn Baldwin *retval = 64; 9074a627952SJohn Baldwin else 9084a627952SJohn Baldwin *retval = 32; 909681a5bbeSBoris Popov break; 910681a5bbeSBoris Popov case _PC_NAME_MAX: 9113419dc99SBoris Popov *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 912681a5bbeSBoris Popov break; 913681a5bbeSBoris Popov case _PC_PATH_MAX: 914681a5bbeSBoris Popov *retval = 800; /* XXX: a correct one ? */ 915681a5bbeSBoris Popov break; 9164a627952SJohn Baldwin case _PC_NO_TRUNC: 9174a627952SJohn Baldwin *retval = 1; 9184a627952SJohn Baldwin break; 919681a5bbeSBoris Popov default: 92015a88f81SJohn Baldwin error = vop_stdpathconf(ap); 921681a5bbeSBoris Popov } 922681a5bbeSBoris Popov return error; 923681a5bbeSBoris Popov } 924681a5bbeSBoris Popov 925681a5bbeSBoris Popov static int 926681a5bbeSBoris Popov smbfs_strategy (ap) 927681a5bbeSBoris Popov struct vop_strategy_args /* { 928681a5bbeSBoris Popov struct buf *a_bp 929681a5bbeSBoris Popov } */ *ap; 930681a5bbeSBoris Popov { 931681a5bbeSBoris Popov struct buf *bp=ap->a_bp; 932681a5bbeSBoris Popov struct ucred *cr; 933b1c996c4SBoris Popov struct thread *td; 934681a5bbeSBoris Popov 935681a5bbeSBoris Popov SMBVDEBUG("\n"); 936681a5bbeSBoris Popov if (bp->b_flags & B_ASYNC) 937b1c996c4SBoris Popov td = (struct thread *)0; 938681a5bbeSBoris Popov else 939b1c996c4SBoris Popov td = curthread; /* XXX */ 940681a5bbeSBoris Popov if (bp->b_iocmd == BIO_READ) 941681a5bbeSBoris Popov cr = bp->b_rcred; 942681a5bbeSBoris Popov else 943681a5bbeSBoris Popov cr = bp->b_wcred; 944681a5bbeSBoris Popov 945681a5bbeSBoris Popov if ((bp->b_flags & B_ASYNC) == 0 ) 94613fd4d21SBjoern A. Zeeb (void)smbfs_doio(ap->a_vp, bp, cr, td); 9470da50f6eSEdward Tomasz Napierala return (0); 948681a5bbeSBoris Popov } 949681a5bbeSBoris Popov 9508e67c454STim J. Robbins int 9518e67c454STim J. Robbins smbfs_ioctl(ap) 9528e67c454STim J. Robbins struct vop_ioctl_args /* { 9538e67c454STim J. Robbins struct vnode *a_vp; 9548e67c454STim J. Robbins u_long a_command; 9558e67c454STim J. Robbins caddr_t a_data; 9568e67c454STim J. Robbins int fflag; 9578e67c454STim J. Robbins struct ucred *cred; 9588e67c454STim J. Robbins struct thread *td; 9598e67c454STim J. Robbins } */ *ap; 9608e67c454STim J. Robbins { 9618e67c454STim J. Robbins return ENOTTY; 9628e67c454STim J. Robbins } 9638e67c454STim J. Robbins 964681a5bbeSBoris Popov static char smbfs_atl[] = "rhsvda"; 965681a5bbeSBoris Popov static int 966681a5bbeSBoris Popov smbfs_getextattr(struct vop_getextattr_args *ap) 967681a5bbeSBoris Popov /* { 968681a5bbeSBoris Popov IN struct vnode *a_vp; 969681a5bbeSBoris Popov IN char *a_name; 970681a5bbeSBoris Popov INOUT struct uio *a_uio; 971681a5bbeSBoris Popov IN struct ucred *a_cred; 972b1c996c4SBoris Popov IN struct thread *a_td; 973681a5bbeSBoris Popov }; 974681a5bbeSBoris Popov */ 975681a5bbeSBoris Popov { 976681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 977b1c996c4SBoris Popov struct thread *td = ap->a_td; 978681a5bbeSBoris Popov struct ucred *cred = ap->a_cred; 979681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 980681a5bbeSBoris Popov const char *name = ap->a_name; 981681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 982681a5bbeSBoris Popov struct vattr vattr; 983681a5bbeSBoris Popov char buf[10]; 984681a5bbeSBoris Popov int i, attr, error; 985681a5bbeSBoris Popov 986b1c996c4SBoris Popov error = VOP_ACCESS(vp, VREAD, cred, td); 987681a5bbeSBoris Popov if (error) 988681a5bbeSBoris Popov return error; 9890359a12eSAttilio Rao error = VOP_GETATTR(vp, &vattr, cred); 990681a5bbeSBoris Popov if (error) 991681a5bbeSBoris Popov return error; 992681a5bbeSBoris Popov if (strcmp(name, "dosattr") == 0) { 993681a5bbeSBoris Popov attr = np->n_dosattr; 994681a5bbeSBoris Popov for (i = 0; i < 6; i++, attr >>= 1) 995681a5bbeSBoris Popov buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 996681a5bbeSBoris Popov buf[i] = 0; 997681a5bbeSBoris Popov error = uiomove(buf, i, uio); 998681a5bbeSBoris Popov 999681a5bbeSBoris Popov } else 1000681a5bbeSBoris Popov error = EINVAL; 1001681a5bbeSBoris Popov return error; 1002681a5bbeSBoris Popov } 1003681a5bbeSBoris Popov 1004681a5bbeSBoris Popov /* 1005681a5bbeSBoris Popov * Since we expected to support F_GETLK (and SMB protocol has no such function), 1006681a5bbeSBoris Popov * it is necessary to use lf_advlock(). It would be nice if this function had 1007681a5bbeSBoris Popov * a callback mechanism because it will help to improve a level of consistency. 1008681a5bbeSBoris Popov */ 1009681a5bbeSBoris Popov int 1010681a5bbeSBoris Popov smbfs_advlock(ap) 1011681a5bbeSBoris Popov struct vop_advlock_args /* { 1012681a5bbeSBoris Popov struct vnode *a_vp; 1013681a5bbeSBoris Popov caddr_t a_id; 1014681a5bbeSBoris Popov int a_op; 1015681a5bbeSBoris Popov struct flock *a_fl; 1016681a5bbeSBoris Popov int a_flags; 1017681a5bbeSBoris Popov } */ *ap; 1018681a5bbeSBoris Popov { 1019681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 1020681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 1021681a5bbeSBoris Popov struct flock *fl = ap->a_fl; 1022681a5bbeSBoris Popov caddr_t id = (caddr_t)1 /* ap->a_id */; 1023681a5bbeSBoris Popov /* int flags = ap->a_flags;*/ 1024b1c996c4SBoris Popov struct thread *td = curthread; 1025afe09751SDavide Italiano struct smb_cred *scred; 102647790174SAndrey A. Chernov u_quad_t size; 1027fcbe9614SAndrey A. Chernov off_t start, end, oadd; 1028681a5bbeSBoris Popov int error, lkop; 1029681a5bbeSBoris Popov 1030681a5bbeSBoris Popov if (vp->v_type == VDIR) { 1031681a5bbeSBoris Popov /* 1032681a5bbeSBoris Popov * SMB protocol have no support for directory locking. 1033681a5bbeSBoris Popov * Although locks can be processed on local machine, I don't 1034681a5bbeSBoris Popov * think that this is a good idea, because some programs 1035681a5bbeSBoris Popov * can work wrong assuming directory is locked. So, we just 1036681a5bbeSBoris Popov * return 'operation not supported 1037681a5bbeSBoris Popov */ 1038681a5bbeSBoris Popov return EOPNOTSUPP; 1039681a5bbeSBoris Popov } 1040681a5bbeSBoris Popov size = np->n_size; 1041681a5bbeSBoris Popov switch (fl->l_whence) { 104215924778SAndrey A. Chernov 1043681a5bbeSBoris Popov case SEEK_SET: 1044681a5bbeSBoris Popov case SEEK_CUR: 1045681a5bbeSBoris Popov start = fl->l_start; 1046681a5bbeSBoris Popov break; 104715924778SAndrey A. Chernov 1048681a5bbeSBoris Popov case SEEK_END: 104915924778SAndrey A. Chernov if (size > OFF_MAX || 105015924778SAndrey A. Chernov (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 105147790174SAndrey A. Chernov return EOVERFLOW; 105215924778SAndrey A. Chernov start = size + fl->l_start; 1053bbf6984cSAndrey A. Chernov break; 105415924778SAndrey A. Chernov 1055681a5bbeSBoris Popov default: 1056681a5bbeSBoris Popov return EINVAL; 1057681a5bbeSBoris Popov } 1058681a5bbeSBoris Popov if (start < 0) 1059681a5bbeSBoris Popov return EINVAL; 1060e3e2c03dSAndrey A. Chernov if (fl->l_len < 0) { 1061ea4313e3SAndrey A. Chernov if (start == 0) 1062e3e2c03dSAndrey A. Chernov return EINVAL; 1063e3e2c03dSAndrey A. Chernov end = start - 1; 1064ea4313e3SAndrey A. Chernov start += fl->l_len; 1065ea4313e3SAndrey A. Chernov if (start < 0) 1066ea4313e3SAndrey A. Chernov return EINVAL; 1067e3e2c03dSAndrey A. Chernov } else if (fl->l_len == 0) 1068681a5bbeSBoris Popov end = -1; 1069681a5bbeSBoris Popov else { 1070fcbe9614SAndrey A. Chernov oadd = fl->l_len - 1; 107147790174SAndrey A. Chernov if (oadd > OFF_MAX - start) 107247790174SAndrey A. Chernov return EOVERFLOW; 107347790174SAndrey A. Chernov end = start + oadd; 1074681a5bbeSBoris Popov } 1075afe09751SDavide Italiano scred = smbfs_malloc_scred(); 1076afe09751SDavide Italiano smb_makescred(scred, td, td->td_ucred); 1077681a5bbeSBoris Popov switch (ap->a_op) { 1078681a5bbeSBoris Popov case F_SETLK: 1079681a5bbeSBoris Popov switch (fl->l_type) { 1080681a5bbeSBoris Popov case F_WRLCK: 1081681a5bbeSBoris Popov lkop = SMB_LOCK_EXCL; 1082681a5bbeSBoris Popov break; 1083681a5bbeSBoris Popov case F_RDLCK: 1084681a5bbeSBoris Popov lkop = SMB_LOCK_SHARED; 1085681a5bbeSBoris Popov break; 1086681a5bbeSBoris Popov case F_UNLCK: 1087681a5bbeSBoris Popov lkop = SMB_LOCK_RELEASE; 1088681a5bbeSBoris Popov break; 1089681a5bbeSBoris Popov default: 1090afe09751SDavide Italiano smbfs_free_scred(scred); 1091681a5bbeSBoris Popov return EINVAL; 1092681a5bbeSBoris Popov } 1093eab626f1SKonstantin Belousov error = lf_advlock(ap, &vp->v_lockf, size); 1094681a5bbeSBoris Popov if (error) 1095681a5bbeSBoris Popov break; 1096681a5bbeSBoris Popov lkop = SMB_LOCK_EXCL; 1097afe09751SDavide Italiano error = smbfs_smb_lock(np, lkop, id, start, end, scred); 1098681a5bbeSBoris Popov if (error) { 109918121c17SDoug Rabson int oldtype = fl->l_type; 110018121c17SDoug Rabson fl->l_type = F_UNLCK; 1101681a5bbeSBoris Popov ap->a_op = F_UNLCK; 1102eab626f1SKonstantin Belousov lf_advlock(ap, &vp->v_lockf, size); 110318121c17SDoug Rabson fl->l_type = oldtype; 1104681a5bbeSBoris Popov } 1105681a5bbeSBoris Popov break; 1106681a5bbeSBoris Popov case F_UNLCK: 1107eab626f1SKonstantin Belousov lf_advlock(ap, &vp->v_lockf, size); 1108afe09751SDavide Italiano error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, scred); 1109681a5bbeSBoris Popov break; 1110681a5bbeSBoris Popov case F_GETLK: 1111eab626f1SKonstantin Belousov error = lf_advlock(ap, &vp->v_lockf, size); 1112681a5bbeSBoris Popov break; 1113681a5bbeSBoris Popov default: 1114afe09751SDavide Italiano smbfs_free_scred(scred); 1115681a5bbeSBoris Popov return EINVAL; 1116681a5bbeSBoris Popov } 1117afe09751SDavide Italiano smbfs_free_scred(scred); 1118681a5bbeSBoris Popov return error; 1119681a5bbeSBoris Popov } 1120681a5bbeSBoris Popov 1121681a5bbeSBoris Popov static int 1122681a5bbeSBoris Popov smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 1123681a5bbeSBoris Popov { 112452b2c8e2SOleksandr Tymoshenko static const char *badchars = "*/:<>?"; 112552b2c8e2SOleksandr Tymoshenko static const char *badchars83 = " +|,[]=;"; 1126681a5bbeSBoris Popov const char *cp; 1127681a5bbeSBoris Popov int i, error; 1128681a5bbeSBoris Popov 112972f6a0faSColin Percival /* 113072f6a0faSColin Percival * Backslash characters, being a path delimiter, are prohibited 113172f6a0faSColin Percival * within a path component even for LOOKUP operations. 113272f6a0faSColin Percival */ 1133dc15eac0SEd Schouten if (strchr(name, '\\') != NULL) 113472f6a0faSColin Percival return ENOENT; 113572f6a0faSColin Percival 1136681a5bbeSBoris Popov if (nameiop == LOOKUP) 1137681a5bbeSBoris Popov return 0; 1138681a5bbeSBoris Popov error = ENOENT; 1139681a5bbeSBoris Popov if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1140681a5bbeSBoris Popov /* 1141681a5bbeSBoris Popov * Name should conform 8.3 format 1142681a5bbeSBoris Popov */ 1143681a5bbeSBoris Popov if (nmlen > 12) 1144681a5bbeSBoris Popov return ENAMETOOLONG; 1145dc15eac0SEd Schouten cp = strchr(name, '.'); 1146681a5bbeSBoris Popov if (cp == NULL) 1147681a5bbeSBoris Popov return error; 1148681a5bbeSBoris Popov if (cp == name || (cp - name) > 8) 1149681a5bbeSBoris Popov return error; 1150dc15eac0SEd Schouten cp = strchr(cp + 1, '.'); 1151681a5bbeSBoris Popov if (cp != NULL) 1152681a5bbeSBoris Popov return error; 1153681a5bbeSBoris Popov for (cp = name, i = 0; i < nmlen; i++, cp++) 1154dc15eac0SEd Schouten if (strchr(badchars83, *cp) != NULL) 1155681a5bbeSBoris Popov return error; 1156681a5bbeSBoris Popov } 1157681a5bbeSBoris Popov for (cp = name, i = 0; i < nmlen; i++, cp++) 1158dc15eac0SEd Schouten if (strchr(badchars, *cp) != NULL) 1159681a5bbeSBoris Popov return error; 1160681a5bbeSBoris Popov return 0; 1161681a5bbeSBoris Popov } 1162681a5bbeSBoris Popov 1163681a5bbeSBoris Popov /* 1164681a5bbeSBoris Popov * Things go even weird without fixed inode numbers... 1165681a5bbeSBoris Popov */ 1166681a5bbeSBoris Popov int 1167681a5bbeSBoris Popov smbfs_lookup(ap) 1168681a5bbeSBoris Popov struct vop_lookup_args /* { 1169681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 1170681a5bbeSBoris Popov struct vnode *a_dvp; 1171681a5bbeSBoris Popov struct vnode **a_vpp; 1172681a5bbeSBoris Popov struct componentname *a_cnp; 1173681a5bbeSBoris Popov } */ *ap; 1174681a5bbeSBoris Popov { 1175681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 1176b1c996c4SBoris Popov struct thread *td = cnp->cn_thread; 1177681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 1178681a5bbeSBoris Popov struct vnode **vpp = ap->a_vpp; 1179681a5bbeSBoris Popov struct vnode *vp; 1180681a5bbeSBoris Popov struct smbmount *smp; 1181681a5bbeSBoris Popov struct mount *mp = dvp->v_mount; 1182681a5bbeSBoris Popov struct smbnode *dnp; 1183681a5bbeSBoris Popov struct smbfattr fattr, *fap; 1184afe09751SDavide Italiano struct smb_cred *scred; 1185681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 1186681a5bbeSBoris Popov int flags = cnp->cn_flags; 1187681a5bbeSBoris Popov int nameiop = cnp->cn_nameiop; 1188681a5bbeSBoris Popov int nmlen = cnp->cn_namelen; 1189da1c9cb2SJeff Roberson int error, islastcn, isdot; 1190b4484bf0STim J. Robbins int killit; 1191681a5bbeSBoris Popov 1192681a5bbeSBoris Popov SMBVDEBUG("\n"); 1193681a5bbeSBoris Popov if (dvp->v_type != VDIR) 1194681a5bbeSBoris Popov return ENOTDIR; 1195e6e370a7SJeff Roberson if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 1196681a5bbeSBoris Popov SMBFSERR("invalid '..'\n"); 1197681a5bbeSBoris Popov return EIO; 1198681a5bbeSBoris Popov } 1199681a5bbeSBoris Popov islastcn = flags & ISLASTCN; 1200681a5bbeSBoris Popov if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1201681a5bbeSBoris Popov return EROFS; 1202b1c996c4SBoris Popov if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) 1203681a5bbeSBoris Popov return error; 1204681a5bbeSBoris Popov smp = VFSTOSMBFS(mp); 1205681a5bbeSBoris Popov dnp = VTOSMB(dvp); 1206681a5bbeSBoris Popov isdot = (nmlen == 1 && name[0] == '.'); 1207681a5bbeSBoris Popov 1208681a5bbeSBoris Popov error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1209681a5bbeSBoris Popov 1210681a5bbeSBoris Popov if (error) 1211681a5bbeSBoris Popov return ENOENT; 1212681a5bbeSBoris Popov 1213bf40d24aSJohn Baldwin error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 1214681a5bbeSBoris Popov SMBVDEBUG("cache_lookup returned %d\n", error); 1215681a5bbeSBoris Popov if (error > 0) 1216681a5bbeSBoris Popov return error; 1217681a5bbeSBoris Popov if (error) { /* name was found */ 1218681a5bbeSBoris Popov struct vattr vattr; 1219681a5bbeSBoris Popov 1220b4484bf0STim J. Robbins killit = 0; 1221e8943128SXin LI vp = *vpp; 12220359a12eSAttilio Rao error = VOP_GETATTR(vp, &vattr, cnp->cn_cred); 1223b4484bf0STim J. Robbins /* 1224b4484bf0STim J. Robbins * If the file type on the server is inconsistent 1225b4484bf0STim J. Robbins * with what it was when we created the vnode, 1226b4484bf0STim J. Robbins * kill the bogus vnode now and fall through to 1227b4484bf0STim J. Robbins * the code below to create a new one with the 1228b4484bf0STim J. Robbins * right type. 1229b4484bf0STim J. Robbins */ 1230b4484bf0STim J. Robbins if (error == 0 && 1231b4484bf0STim J. Robbins ((vp->v_type == VDIR && 1232b4484bf0STim J. Robbins (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || 1233b4484bf0STim J. Robbins (vp->v_type == VREG && 1234b4484bf0STim J. Robbins (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) 1235b4484bf0STim J. Robbins killit = 1; 1236b4484bf0STim J. Robbins else if (error == 0 1237681a5bbeSBoris Popov /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1238681a5bbeSBoris Popov if (nameiop != LOOKUP && islastcn) 1239681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1240681a5bbeSBoris Popov SMBVDEBUG("use cached vnode\n"); 1241681a5bbeSBoris Popov return (0); 1242681a5bbeSBoris Popov } 1243681a5bbeSBoris Popov cache_purge(vp); 1244f6576f19SJeff Roberson /* 1245f6576f19SJeff Roberson * XXX This is not quite right, if '.' is 1246f6576f19SJeff Roberson * inconsistent, we really need to start the lookup 1247f6576f19SJeff Roberson * all over again. Hopefully there is some other 1248f6576f19SJeff Roberson * guarantee that prevents this case from happening. 1249f6576f19SJeff Roberson */ 1250f6576f19SJeff Roberson if (killit && vp != dvp) 1251b4484bf0STim J. Robbins vgone(vp); 1252f6576f19SJeff Roberson if (vp != dvp) 12538da00465SJeff Roberson vput(vp); 1254f6576f19SJeff Roberson else 1255f6576f19SJeff Roberson vrele(vp); 1256681a5bbeSBoris Popov *vpp = NULLVP; 1257681a5bbeSBoris Popov } 1258681a5bbeSBoris Popov /* 1259681a5bbeSBoris Popov * entry is not in the cache or has been expired 1260681a5bbeSBoris Popov */ 1261681a5bbeSBoris Popov error = 0; 1262681a5bbeSBoris Popov *vpp = NULLVP; 1263afe09751SDavide Italiano scred = smbfs_malloc_scred(); 1264afe09751SDavide Italiano smb_makescred(scred, td, cnp->cn_cred); 1265681a5bbeSBoris Popov fap = &fattr; 1266681a5bbeSBoris Popov if (flags & ISDOTDOT) { 1267ce589ae2SDavide Italiano /* 1268ce589ae2SDavide Italiano * In the DOTDOT case, don't go over-the-wire 1269ce589ae2SDavide Italiano * in order to request attributes. We already 1270ce589ae2SDavide Italiano * know it's a directory and subsequent call to 1271ce589ae2SDavide Italiano * smbfs_getattr() will restore consistency. 1272ce589ae2SDavide Italiano * 1273ce589ae2SDavide Italiano */ 1274ce589ae2SDavide Italiano SMBVDEBUG("smbfs_smb_lookup: dotdot\n"); 1275ce589ae2SDavide Italiano } else if (isdot) { 1276ce589ae2SDavide Italiano error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1277ce589ae2SDavide Italiano SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1278ce589ae2SDavide Italiano } 1279ce589ae2SDavide Italiano else { 1280afe09751SDavide Italiano error = smbfs_smb_lookup(dnp, name, nmlen, fap, scred); 1281681a5bbeSBoris Popov SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1282681a5bbeSBoris Popov } 1283681a5bbeSBoris Popov if (error && error != ENOENT) 1284afe09751SDavide Italiano goto out; 1285681a5bbeSBoris Popov if (error) { /* entry not found */ 1286681a5bbeSBoris Popov /* 1287681a5bbeSBoris Popov * Handle RENAME or CREATE case... 1288681a5bbeSBoris Popov */ 1289da1c9cb2SJeff Roberson if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { 12906e8681aaSBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 12916e8681aaSBoris Popov if (error) 1292afe09751SDavide Italiano goto out; 1293681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1294afe09751SDavide Italiano error = EJUSTRETURN; 1295afe09751SDavide Italiano goto out; 1296681a5bbeSBoris Popov } 1297afe09751SDavide Italiano error = ENOENT; 1298afe09751SDavide Italiano goto out; 1299681a5bbeSBoris Popov }/* else { 1300681a5bbeSBoris Popov SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1301681a5bbeSBoris Popov }*/ 1302681a5bbeSBoris Popov /* 1303681a5bbeSBoris Popov * handle DELETE case ... 1304681a5bbeSBoris Popov */ 1305681a5bbeSBoris Popov if (nameiop == DELETE && islastcn) { /* delete last component */ 1306b1c996c4SBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1307681a5bbeSBoris Popov if (error) 1308afe09751SDavide Italiano goto out; 1309681a5bbeSBoris Popov if (isdot) { 1310681a5bbeSBoris Popov VREF(dvp); 1311681a5bbeSBoris Popov *vpp = dvp; 1312afe09751SDavide Italiano goto out; 1313681a5bbeSBoris Popov } 1314681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1315681a5bbeSBoris Popov if (error) 1316afe09751SDavide Italiano goto out; 1317681a5bbeSBoris Popov *vpp = vp; 1318681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1319afe09751SDavide Italiano goto out; 1320681a5bbeSBoris Popov } 1321da1c9cb2SJeff Roberson if (nameiop == RENAME && islastcn) { 1322b1c996c4SBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1323681a5bbeSBoris Popov if (error) 1324afe09751SDavide Italiano goto out; 1325afe09751SDavide Italiano if (isdot) { 1326afe09751SDavide Italiano error = EISDIR; 1327afe09751SDavide Italiano goto out; 1328afe09751SDavide Italiano } 1329681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1330681a5bbeSBoris Popov if (error) 1331afe09751SDavide Italiano goto out; 1332681a5bbeSBoris Popov *vpp = vp; 1333681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1334afe09751SDavide Italiano goto out; 1335681a5bbeSBoris Popov } 1336681a5bbeSBoris Popov if (flags & ISDOTDOT) { 13379dbe0b12SDavide Italiano mp = dvp->v_mount; 13389dbe0b12SDavide Italiano error = vfs_busy(mp, MBF_NOWAIT); 13399dbe0b12SDavide Italiano if (error != 0) { 13409dbe0b12SDavide Italiano vfs_ref(mp); 13419dbe0b12SDavide Italiano VOP_UNLOCK(dvp, 0); 13429dbe0b12SDavide Italiano error = vfs_busy(mp, 0); 13439dbe0b12SDavide Italiano vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 13449dbe0b12SDavide Italiano vfs_rel(mp); 1345c7d2e4cfSDavide Italiano if (error) { 1346c7d2e4cfSDavide Italiano error = ENOENT; 1347c7d2e4cfSDavide Italiano goto out; 1348c7d2e4cfSDavide Italiano } 1349abd80ddbSMateusz Guzik if (VN_IS_DOOMED(dvp)) { 13509dbe0b12SDavide Italiano vfs_unbusy(mp); 1351c7d2e4cfSDavide Italiano error = ENOENT; 1352c7d2e4cfSDavide Italiano goto out; 13539dbe0b12SDavide Italiano } 13549dbe0b12SDavide Italiano } 135522db15c0SAttilio Rao VOP_UNLOCK(dvp, 0); 1356681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 13579dbe0b12SDavide Italiano vfs_unbusy(mp); 1358cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1359abd80ddbSMateusz Guzik if (VN_IS_DOOMED(dvp)) { 13609dbe0b12SDavide Italiano if (error == 0) 13619dbe0b12SDavide Italiano vput(vp); 13629dbe0b12SDavide Italiano error = ENOENT; 13639dbe0b12SDavide Italiano } 13644585e3acSJeff Roberson if (error) 1365afe09751SDavide Italiano goto out; 1366681a5bbeSBoris Popov *vpp = vp; 1367681a5bbeSBoris Popov } else if (isdot) { 1368681a5bbeSBoris Popov vref(dvp); 1369681a5bbeSBoris Popov *vpp = dvp; 1370681a5bbeSBoris Popov } else { 1371681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1372681a5bbeSBoris Popov if (error) 1373afe09751SDavide Italiano goto out; 1374681a5bbeSBoris Popov *vpp = vp; 1375681a5bbeSBoris Popov SMBVDEBUG("lookup: getnewvp!\n"); 1376681a5bbeSBoris Popov } 1377681a5bbeSBoris Popov if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1378681a5bbeSBoris Popov /* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1379681a5bbeSBoris Popov cache_enter(dvp, *vpp, cnp); 1380681a5bbeSBoris Popov } 1381afe09751SDavide Italiano out: 1382afe09751SDavide Italiano smbfs_free_scred(scred); 1383afe09751SDavide Italiano return (error); 1384681a5bbeSBoris Popov } 1385