14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000-2001 Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 354bff34e3Sthurlow /* 364bff34e3Sthurlow * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 374bff34e3Sthurlow * Use is subject to license terms. 384bff34e3Sthurlow */ 394bff34e3Sthurlow 404bff34e3Sthurlow #pragma ident "%Z%%M% %I% %E% SMI" 414bff34e3Sthurlow 424bff34e3Sthurlow #include <sys/systm.h> 434bff34e3Sthurlow #include <sys/cred.h> 444bff34e3Sthurlow #include <sys/vnode.h> 454bff34e3Sthurlow #include <sys/vfs.h> 46*7568150aSgwr #include <sys/filio.h> 474bff34e3Sthurlow #include <sys/uio.h> 484bff34e3Sthurlow #include <sys/dirent.h> 494bff34e3Sthurlow #include <sys/errno.h> 504bff34e3Sthurlow #include <sys/sysmacros.h> 514bff34e3Sthurlow #include <sys/kmem.h> 524bff34e3Sthurlow #include <sys/cmn_err.h> 534bff34e3Sthurlow #include <sys/dnlc.h> 544bff34e3Sthurlow #include <sys/vfs_opreg.h> 554bff34e3Sthurlow #include <sys/policy.h> 564bff34e3Sthurlow 574bff34e3Sthurlow #include <netsmb/smb_osdep.h> 584bff34e3Sthurlow #include <netsmb/smb.h> 594bff34e3Sthurlow #include <netsmb/smb_conn.h> 604bff34e3Sthurlow #include <netsmb/smb_subr.h> 614bff34e3Sthurlow 624bff34e3Sthurlow #include <smbfs/smbfs.h> 634bff34e3Sthurlow #include <smbfs/smbfs_node.h> 644bff34e3Sthurlow #include <smbfs/smbfs_subr.h> 654bff34e3Sthurlow 66*7568150aSgwr #include <sys/fs/smbfs_ioctl.h> 674bff34e3Sthurlow #include <fs/fs_subr.h> 684bff34e3Sthurlow 694bff34e3Sthurlow /* 704bff34e3Sthurlow * These characters are illegal in NTFS file names. 714bff34e3Sthurlow * ref: http://support.microsoft.com/kb/147438 724bff34e3Sthurlow */ 734bff34e3Sthurlow static const char illegal_chars[] = { 744bff34e3Sthurlow '\\', /* back slash */ 754bff34e3Sthurlow '/', /* slash */ 764bff34e3Sthurlow ':', /* colon */ 774bff34e3Sthurlow '*', /* asterisk */ 784bff34e3Sthurlow '?', /* question mark */ 794bff34e3Sthurlow '"', /* double quote */ 804bff34e3Sthurlow '<', /* less than sign */ 814bff34e3Sthurlow '>', /* greater than sign */ 824bff34e3Sthurlow '|', /* vertical bar */ 834bff34e3Sthurlow 0 844bff34e3Sthurlow }; 854bff34e3Sthurlow 864bff34e3Sthurlow /* 874bff34e3Sthurlow * Turning this on causes nodes to be created in the cache 884bff34e3Sthurlow * during directory listings. The "fast" claim is debatable, 894bff34e3Sthurlow * and the effects on the cache can be undesirable. 904bff34e3Sthurlow */ 914bff34e3Sthurlow 924bff34e3Sthurlow /* local static function defines */ 934bff34e3Sthurlow 944bff34e3Sthurlow static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, 954bff34e3Sthurlow int dnlc, caller_context_t *); 964bff34e3Sthurlow static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, 974bff34e3Sthurlow cred_t *cr, caller_context_t *); 984bff34e3Sthurlow static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *); 994bff34e3Sthurlow static int smbfs_accessx(void *, int, cred_t *); 1004bff34e3Sthurlow static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 1014bff34e3Sthurlow caller_context_t *); 1024bff34e3Sthurlow /* 1034bff34e3Sthurlow * These are the vnode ops routines which implement the vnode interface to 1044bff34e3Sthurlow * the networked file system. These routines just take their parameters, 1054bff34e3Sthurlow * make them look networkish by putting the right info into interface structs, 1064bff34e3Sthurlow * and then calling the appropriate remote routine(s) to do the work. 1074bff34e3Sthurlow * 1084bff34e3Sthurlow * Note on directory name lookup cacheing: If we detect a stale fhandle, 1094bff34e3Sthurlow * we purge the directory cache relative to that vnode. This way, the 1104bff34e3Sthurlow * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for 1114bff34e3Sthurlow * more details on smbnode locking. 1124bff34e3Sthurlow */ 1134bff34e3Sthurlow 1144bff34e3Sthurlow static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *); 1154bff34e3Sthurlow static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *, 1164bff34e3Sthurlow caller_context_t *); 1174bff34e3Sthurlow static int smbfs_read(vnode_t *, struct uio *, int, cred_t *, 1184bff34e3Sthurlow caller_context_t *); 1194bff34e3Sthurlow static int smbfs_write(vnode_t *, struct uio *, int, cred_t *, 1204bff34e3Sthurlow caller_context_t *); 121*7568150aSgwr static int smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *, 122*7568150aSgwr caller_context_t *); 1234bff34e3Sthurlow static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *, 1244bff34e3Sthurlow caller_context_t *); 1254bff34e3Sthurlow static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *, 1264bff34e3Sthurlow caller_context_t *); 1274bff34e3Sthurlow static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *); 1284bff34e3Sthurlow static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *); 1294bff34e3Sthurlow static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *); 1304bff34e3Sthurlow static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *, 1314bff34e3Sthurlow int, vnode_t *, cred_t *, caller_context_t *, 1324bff34e3Sthurlow int *, pathname_t *); 1334bff34e3Sthurlow static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl, 1344bff34e3Sthurlow int, vnode_t **, cred_t *, int, caller_context_t *, 1354bff34e3Sthurlow vsecattr_t *); 1364bff34e3Sthurlow static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *, 1374bff34e3Sthurlow int); 1384bff34e3Sthurlow static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *, 1394bff34e3Sthurlow caller_context_t *, int); 1404bff34e3Sthurlow static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **, 1414bff34e3Sthurlow cred_t *, caller_context_t *, int, vsecattr_t *); 1424bff34e3Sthurlow static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *, 1434bff34e3Sthurlow caller_context_t *, int); 1444bff34e3Sthurlow static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *, 1454bff34e3Sthurlow caller_context_t *, int); 1464bff34e3Sthurlow static int smbfs_rwlock(vnode_t *, int, caller_context_t *); 1474bff34e3Sthurlow static void smbfs_rwunlock(vnode_t *, int, caller_context_t *); 1484bff34e3Sthurlow static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *); 1494bff34e3Sthurlow static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t, 1504bff34e3Sthurlow struct flk_callback *, cred_t *, caller_context_t *); 1514bff34e3Sthurlow static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t, 1524bff34e3Sthurlow cred_t *, caller_context_t *); 1534bff34e3Sthurlow static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *, 1544bff34e3Sthurlow caller_context_t *); 155*7568150aSgwr static int smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 156*7568150aSgwr caller_context_t *); 157*7568150aSgwr static int smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 158*7568150aSgwr caller_context_t *); 1594bff34e3Sthurlow static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *, 1604bff34e3Sthurlow caller_context_t *); 1614bff34e3Sthurlow 1624bff34e3Sthurlow /* Dummy function to use until correct function is ported in */ 1634bff34e3Sthurlow int noop_vnodeop() { 1644bff34e3Sthurlow return (0); 1654bff34e3Sthurlow } 1664bff34e3Sthurlow 1674bff34e3Sthurlow struct vnodeops *smbfs_vnodeops = NULL; 1684bff34e3Sthurlow 1694bff34e3Sthurlow /* 1704bff34e3Sthurlow * Most unimplemented ops will return ENOSYS because of fs_nosys(). 1714bff34e3Sthurlow * The only ops where that won't work are ACCESS (due to open(2) 172*7568150aSgwr * failures) and ... (anything else left?) 1734bff34e3Sthurlow */ 1744bff34e3Sthurlow const fs_operation_def_t smbfs_vnodeops_template[] = { 175*7568150aSgwr { VOPNAME_OPEN, { .vop_open = smbfs_open } }, 176*7568150aSgwr { VOPNAME_CLOSE, { .vop_close = smbfs_close } }, 177*7568150aSgwr { VOPNAME_READ, { .vop_read = smbfs_read } }, 178*7568150aSgwr { VOPNAME_WRITE, { .vop_write = smbfs_write } }, 179*7568150aSgwr { VOPNAME_IOCTL, { .vop_ioctl = smbfs_ioctl } }, 180*7568150aSgwr { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } }, 181*7568150aSgwr { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } }, 182*7568150aSgwr { VOPNAME_ACCESS, { .vop_access = smbfs_access } }, 183*7568150aSgwr { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } }, 184*7568150aSgwr { VOPNAME_CREATE, { .vop_create = smbfs_create } }, 185*7568150aSgwr { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } }, 186*7568150aSgwr { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */ 187*7568150aSgwr { VOPNAME_RENAME, { .vop_rename = smbfs_rename } }, 188*7568150aSgwr { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } }, 189*7568150aSgwr { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } }, 190*7568150aSgwr { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } }, 191*7568150aSgwr { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */ 192*7568150aSgwr { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */ 193*7568150aSgwr { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } }, 194*7568150aSgwr { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } }, 195*7568150aSgwr { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */ 196*7568150aSgwr { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } }, 197*7568150aSgwr { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } }, 198*7568150aSgwr { VOPNAME_SEEK, { .vop_seek = smbfs_seek } }, 199*7568150aSgwr { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } }, 200*7568150aSgwr { VOPNAME_SPACE, { .vop_space = smbfs_space } }, 201*7568150aSgwr { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */ 202*7568150aSgwr { VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */ 203*7568150aSgwr { VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */ 204*7568150aSgwr { VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */ 205*7568150aSgwr { VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */ 206*7568150aSgwr { VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */ 207*7568150aSgwr { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */ 208*7568150aSgwr { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } }, 209*7568150aSgwr { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */ 210*7568150aSgwr { VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr } }, 211*7568150aSgwr { VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr } }, 212*7568150aSgwr { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } }, 2134bff34e3Sthurlow { NULL, NULL } 2144bff34e3Sthurlow }; 2154bff34e3Sthurlow 2164bff34e3Sthurlow /* 2174bff34e3Sthurlow * XXX 2184bff34e3Sthurlow * When new and relevant functionality is enabled, we should be 2194bff34e3Sthurlow * calling vfs_set_feature() to inform callers that pieces of 2204bff34e3Sthurlow * functionality are available, per PSARC 2007/227, e.g. 2214bff34e3Sthurlow * 2224bff34e3Sthurlow * VFSFT_XVATTR Supports xvattr for attrs 2234bff34e3Sthurlow * VFSFT_CASEINSENSITIVE Supports case-insensitive 2244bff34e3Sthurlow * VFSFT_NOCASESENSITIVE NOT case-sensitive 2254bff34e3Sthurlow * VFSFT_DIRENTFLAGS Supports dirent flags 2264bff34e3Sthurlow * VFSFT_ACLONCREATE Supports ACL on create 2274bff34e3Sthurlow * VFSFT_ACEMASKONACCESS Can use ACEMASK for access 2284bff34e3Sthurlow */ 2294bff34e3Sthurlow /* ARGSUSED */ 2304bff34e3Sthurlow static int 2314bff34e3Sthurlow smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 2324bff34e3Sthurlow { 2334bff34e3Sthurlow struct vattr va; 2344bff34e3Sthurlow smbnode_t *np; 2354bff34e3Sthurlow vnode_t *vp; 2364bff34e3Sthurlow u_int32_t rights, rightsrcvd; 2374bff34e3Sthurlow u_int16_t fid, oldfid; 2384bff34e3Sthurlow struct smb_cred scred; 2394bff34e3Sthurlow smbmntinfo_t *smi; 2404bff34e3Sthurlow cred_t *oldcr; 2414bff34e3Sthurlow int attrcacheupdated = 0; 2424bff34e3Sthurlow int tmperror; 2434bff34e3Sthurlow int error = 0; 2444bff34e3Sthurlow 2454bff34e3Sthurlow vp = *vpp; 2464bff34e3Sthurlow np = VTOSMB(vp); 2474bff34e3Sthurlow smi = VTOSMI(vp); 2484bff34e3Sthurlow 2494bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 2504bff34e3Sthurlow return (EIO); 2514bff34e3Sthurlow 2524bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 2534bff34e3Sthurlow return (EIO); 2544bff34e3Sthurlow 2554bff34e3Sthurlow if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */ 2564bff34e3Sthurlow SMBVDEBUG("open eacces vtype=%d\n", vp->v_type); 2574bff34e3Sthurlow return (EACCES); 2584bff34e3Sthurlow } 2594bff34e3Sthurlow 2604bff34e3Sthurlow /* 2614bff34e3Sthurlow * Get exclusive access to n_fid and related stuff. 2624bff34e3Sthurlow * No returns after this until out. 2634bff34e3Sthurlow */ 2644bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 2654bff34e3Sthurlow return (EINTR); 2664bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 2674bff34e3Sthurlow 2684bff34e3Sthurlow /* 2694bff34e3Sthurlow * Directory open is easy. 2704bff34e3Sthurlow */ 2714bff34e3Sthurlow if (vp->v_type == VDIR) { 2724bff34e3Sthurlow np->n_dirrefs++; 2734bff34e3Sthurlow goto have_fid; 2744bff34e3Sthurlow } 2754bff34e3Sthurlow 2764bff34e3Sthurlow /* 2774bff34e3Sthurlow * If caller specified O_TRUNC/FTRUNC, then be sure to set 2784bff34e3Sthurlow * FWRITE (to drive successful setattr(size=0) after open) 2794bff34e3Sthurlow */ 2804bff34e3Sthurlow if (flag & FTRUNC) 2814bff34e3Sthurlow flag |= FWRITE; 2824bff34e3Sthurlow 2834bff34e3Sthurlow /* 2844bff34e3Sthurlow * If we already have it open, check to see if current rights 2854bff34e3Sthurlow * are sufficient for this open. 2864bff34e3Sthurlow */ 2874bff34e3Sthurlow if (np->n_fidrefs) { 2884bff34e3Sthurlow int upgrade = 0; 2894bff34e3Sthurlow 2904bff34e3Sthurlow /* BEGIN CSTYLED */ 2914bff34e3Sthurlow if ((flag & FWRITE) && 2924bff34e3Sthurlow !(np->n_rights & (SA_RIGHT_FILE_WRITE_DATA | 2934bff34e3Sthurlow GENERIC_RIGHT_ALL_ACCESS | 2944bff34e3Sthurlow GENERIC_RIGHT_WRITE_ACCESS))) 2954bff34e3Sthurlow upgrade = 1; 2964bff34e3Sthurlow if ((flag & FREAD) && 2974bff34e3Sthurlow !(np->n_rights & (SA_RIGHT_FILE_READ_DATA | 2984bff34e3Sthurlow GENERIC_RIGHT_ALL_ACCESS | 2994bff34e3Sthurlow GENERIC_RIGHT_READ_ACCESS))) 3004bff34e3Sthurlow upgrade = 1; 3014bff34e3Sthurlow /* END CSTYLED */ 3024bff34e3Sthurlow if (!upgrade) { 3034bff34e3Sthurlow /* 3044bff34e3Sthurlow * the existing open is good enough 3054bff34e3Sthurlow */ 3064bff34e3Sthurlow np->n_fidrefs++; 3074bff34e3Sthurlow goto have_fid; 3084bff34e3Sthurlow } 3094bff34e3Sthurlow } 3104bff34e3Sthurlow rights = np->n_fidrefs ? np->n_rights : 0; 3114bff34e3Sthurlow 3124bff34e3Sthurlow /* 3134bff34e3Sthurlow * we always ask for READ_CONTROL so we can always get the 3144bff34e3Sthurlow * owner/group IDs to satisfy a stat. 3154bff34e3Sthurlow * XXX: verify that works with "drop boxes" 3164bff34e3Sthurlow */ 3174bff34e3Sthurlow rights |= STD_RIGHT_READ_CONTROL_ACCESS; 3184bff34e3Sthurlow if ((flag & FREAD)) 3194bff34e3Sthurlow rights |= SA_RIGHT_FILE_READ_DATA; 3204bff34e3Sthurlow if ((flag & FWRITE)) 3214bff34e3Sthurlow rights |= SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_WRITE_DATA; 3224bff34e3Sthurlow 3234bff34e3Sthurlow /* XXX: open gets the current size, but we don't use it. */ 3244bff34e3Sthurlow error = smbfs_smb_open(np, rights, &scred, &attrcacheupdated, &fid, 3254bff34e3Sthurlow NULL, 0, 0, NULL, &rightsrcvd); 3264bff34e3Sthurlow if (error) 3274bff34e3Sthurlow goto out; 3284bff34e3Sthurlow 3294bff34e3Sthurlow /* 3304bff34e3Sthurlow * We have a new FID and access rights. 3314bff34e3Sthurlow */ 3324bff34e3Sthurlow oldfid = np->n_fid; 3334bff34e3Sthurlow np->n_fid = fid; 3344bff34e3Sthurlow np->n_rights = rightsrcvd; 3354bff34e3Sthurlow np->n_fidrefs++; 3364bff34e3Sthurlow if (np->n_fidrefs > 1) { 3374bff34e3Sthurlow /* 3384bff34e3Sthurlow * We already had it open (presumably because 3394bff34e3Sthurlow * it was open with insufficient rights.) 3404bff34e3Sthurlow * Close old wire-open. 3414bff34e3Sthurlow */ 3424bff34e3Sthurlow tmperror = smbfs_smb_close(smi->smi_share, 3434bff34e3Sthurlow oldfid, &np->n_mtime, &scred); 3444bff34e3Sthurlow if (tmperror) 3454bff34e3Sthurlow SMBVDEBUG("error %d closing %s\n", 3464bff34e3Sthurlow tmperror, np->n_rpath); 3474bff34e3Sthurlow } 3484bff34e3Sthurlow 3494bff34e3Sthurlow /* 3504bff34e3Sthurlow * This thread did the open. 3514bff34e3Sthurlow * Save our credentials too. 3524bff34e3Sthurlow */ 3534bff34e3Sthurlow mutex_enter(&np->r_statelock); 3544bff34e3Sthurlow oldcr = np->r_cred; 3554bff34e3Sthurlow np->r_cred = cr; 3564bff34e3Sthurlow crhold(cr); 3574bff34e3Sthurlow if (oldcr) 3584bff34e3Sthurlow crfree(oldcr); 3594bff34e3Sthurlow mutex_exit(&np->r_statelock); 3604bff34e3Sthurlow 3614bff34e3Sthurlow have_fid: 3624bff34e3Sthurlow /* Get attributes (maybe). */ 3634bff34e3Sthurlow 3644bff34e3Sthurlow 3654bff34e3Sthurlow /* Darwin (derived) code. */ 3664bff34e3Sthurlow 3674bff34e3Sthurlow va.va_mask = AT_MTIME; 3684bff34e3Sthurlow if (np->n_flag & NMODIFIED) 3694bff34e3Sthurlow smbfs_attr_cacheremove(np); 3704bff34e3Sthurlow 3714bff34e3Sthurlow /* 3724bff34e3Sthurlow * Try to get attributes, but don't bail on error. 3734bff34e3Sthurlow * We already hold r_lkserlock/reader so note: 3744bff34e3Sthurlow * this call will recursively take r_lkserlock. 3754bff34e3Sthurlow */ 3764bff34e3Sthurlow tmperror = smbfsgetattr(vp, &va, cr); 3774bff34e3Sthurlow if (tmperror) 3784bff34e3Sthurlow SMBERROR("getattr failed, error=%d", tmperror); 3794bff34e3Sthurlow else 3804bff34e3Sthurlow np->n_mtime.tv_sec = va.va_mtime.tv_sec; 3814bff34e3Sthurlow 3824bff34e3Sthurlow out: 3834bff34e3Sthurlow smb_credrele(&scred); 3844bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 3854bff34e3Sthurlow return (error); 3864bff34e3Sthurlow } 3874bff34e3Sthurlow 3884bff34e3Sthurlow /*ARGSUSED*/ 3894bff34e3Sthurlow static int 3904bff34e3Sthurlow smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, 3914bff34e3Sthurlow caller_context_t *ct) 3924bff34e3Sthurlow { 3934bff34e3Sthurlow smbnode_t *np; 3944bff34e3Sthurlow int error = 0; 3954bff34e3Sthurlow struct smb_cred scred; 3964bff34e3Sthurlow 3974bff34e3Sthurlow np = VTOSMB(vp); 3984bff34e3Sthurlow 3994bff34e3Sthurlow /* 4004bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 4014bff34e3Sthurlow * as we want to do cleanup, etc. 4024bff34e3Sthurlow */ 4034bff34e3Sthurlow 4044bff34e3Sthurlow /* 4054bff34e3Sthurlow * zone_enter(2) prevents processes from changing zones with SMBFS files 4064bff34e3Sthurlow * open; if we happen to get here from the wrong zone we can't do 4074bff34e3Sthurlow * anything over the wire. 4084bff34e3Sthurlow */ 4094bff34e3Sthurlow if (VTOSMI(vp)->smi_zone != curproc->p_zone) { 4104bff34e3Sthurlow /* 4114bff34e3Sthurlow * We could attempt to clean up locks, except we're sure 4124bff34e3Sthurlow * that the current process didn't acquire any locks on 4134bff34e3Sthurlow * the file: any attempt to lock a file belong to another zone 4144bff34e3Sthurlow * will fail, and one can't lock an SMBFS file and then change 4154bff34e3Sthurlow * zones, as that fails too. 4164bff34e3Sthurlow * 4174bff34e3Sthurlow * Returning an error here is the sane thing to do. A 4184bff34e3Sthurlow * subsequent call to VN_RELE() which translates to a 4194bff34e3Sthurlow * smbfs_inactive() will clean up state: if the zone of the 4204bff34e3Sthurlow * vnode's origin is still alive and kicking, an async worker 4214bff34e3Sthurlow * thread will handle the request (from the correct zone), and 4224bff34e3Sthurlow * everything (minus the final smbfs_getattr_otw() call) should 4234bff34e3Sthurlow * be OK. If the zone is going away smbfs_async_inactive() will 4244bff34e3Sthurlow * throw away cached pages inline. 4254bff34e3Sthurlow */ 4264bff34e3Sthurlow return (EIO); 4274bff34e3Sthurlow } 4284bff34e3Sthurlow 4294bff34e3Sthurlow /* 4304bff34e3Sthurlow * If we are using local locking for this filesystem, then 4314bff34e3Sthurlow * release all of the SYSV style record locks. Otherwise, 4324bff34e3Sthurlow * we are doing network locking and we need to release all 4334bff34e3Sthurlow * of the network locks. All of the locks held by this 4344bff34e3Sthurlow * process on this file are released no matter what the 4354bff34e3Sthurlow * incoming reference count is. 4364bff34e3Sthurlow */ 4374bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) { 4384bff34e3Sthurlow cleanlocks(vp, ttoproc(curthread)->p_pid, 0); 4394bff34e3Sthurlow cleanshares(vp, ttoproc(curthread)->p_pid); 4404bff34e3Sthurlow } 4414bff34e3Sthurlow 4424bff34e3Sthurlow if (count > 1) 4434bff34e3Sthurlow return (0); 4444bff34e3Sthurlow /* 4454bff34e3Sthurlow * OK, do "last close" stuff. 4464bff34e3Sthurlow */ 4474bff34e3Sthurlow 4484bff34e3Sthurlow 4494bff34e3Sthurlow /* 4504bff34e3Sthurlow * Do the CIFS close. 4514bff34e3Sthurlow * Darwin code 4524bff34e3Sthurlow */ 4534bff34e3Sthurlow 4544bff34e3Sthurlow /* 4554bff34e3Sthurlow * Exclusive lock for modifying n_fid stuff. 4564bff34e3Sthurlow * Don't want this one ever interruptible. 4574bff34e3Sthurlow */ 4584bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0); 4594bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 4604bff34e3Sthurlow 4614bff34e3Sthurlow error = 0; 4624bff34e3Sthurlow if (vp->v_type == VDIR) { 4634bff34e3Sthurlow struct smbfs_fctx *fctx; 4644bff34e3Sthurlow ASSERT(np->n_dirrefs > 0); 4654bff34e3Sthurlow if (--np->n_dirrefs) 4664bff34e3Sthurlow goto out; 4674bff34e3Sthurlow if ((fctx = np->n_dirseq) != NULL) { 4684bff34e3Sthurlow np->n_dirseq = NULL; 4694bff34e3Sthurlow error = smbfs_smb_findclose(fctx, &scred); 4704bff34e3Sthurlow } 4714bff34e3Sthurlow } else { 4724bff34e3Sthurlow uint16_t ofid; 4734bff34e3Sthurlow ASSERT(np->n_fidrefs > 0); 4744bff34e3Sthurlow if (--np->n_fidrefs) 4754bff34e3Sthurlow goto out; 4764bff34e3Sthurlow if ((ofid = np->n_fid) != SMB_FID_UNUSED) { 4774bff34e3Sthurlow np->n_fid = SMB_FID_UNUSED; 4784bff34e3Sthurlow error = smbfs_smb_close(np->n_mount->smi_share, 4794bff34e3Sthurlow ofid, NULL, &scred); 4804bff34e3Sthurlow } 4814bff34e3Sthurlow } 4824bff34e3Sthurlow if (error) { 4834bff34e3Sthurlow SMBERROR("error %d closing %s\n", 4844bff34e3Sthurlow error, np->n_rpath); 4854bff34e3Sthurlow } 4864bff34e3Sthurlow 4874bff34e3Sthurlow if (np->n_flag & NATTRCHANGED) 4884bff34e3Sthurlow smbfs_attr_cacheremove(np); 4894bff34e3Sthurlow 4904bff34e3Sthurlow out: 4914bff34e3Sthurlow smb_credrele(&scred); 4924bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 4934bff34e3Sthurlow 4944bff34e3Sthurlow /* don't return any errors */ 4954bff34e3Sthurlow return (0); 4964bff34e3Sthurlow } 4974bff34e3Sthurlow 4984bff34e3Sthurlow /* ARGSUSED */ 4994bff34e3Sthurlow static int 5004bff34e3Sthurlow smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 5014bff34e3Sthurlow caller_context_t *ct) 5024bff34e3Sthurlow { 5034bff34e3Sthurlow int error; 5044bff34e3Sthurlow struct vattr va; 5054bff34e3Sthurlow smbmntinfo_t *smi; 5064bff34e3Sthurlow smbnode_t *np; 5074bff34e3Sthurlow /* u_offset_t off; */ 5084bff34e3Sthurlow /* offset_t diff; */ 5094bff34e3Sthurlow 5104bff34e3Sthurlow np = VTOSMB(vp); 5114bff34e3Sthurlow smi = VTOSMI(vp); 5124bff34e3Sthurlow 5134bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 5144bff34e3Sthurlow return (EIO); 5154bff34e3Sthurlow 5164bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 5174bff34e3Sthurlow return (EIO); 5184bff34e3Sthurlow 5194bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 5204bff34e3Sthurlow 5214bff34e3Sthurlow if (vp->v_type != VREG) 5224bff34e3Sthurlow return (EISDIR); 5234bff34e3Sthurlow 5244bff34e3Sthurlow if (uiop->uio_resid == 0) 5254bff34e3Sthurlow return (0); 5264bff34e3Sthurlow 5274bff34e3Sthurlow /* 5284bff34e3Sthurlow * Like NFS3, just check for 63-bit overflow. 5294bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 5304bff34e3Sthurlow * when it has to fallback to a 32-bit call. 5314bff34e3Sthurlow */ 5324bff34e3Sthurlow if (uiop->uio_loffset < 0 || 5334bff34e3Sthurlow uiop->uio_loffset + uiop->uio_resid < 0) 5344bff34e3Sthurlow return (EINVAL); 5354bff34e3Sthurlow 5364bff34e3Sthurlow /* Shared lock for n_fid use in smbfs_readvnode */ 5374bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 5384bff34e3Sthurlow return (EINTR); 5394bff34e3Sthurlow 5404bff34e3Sthurlow /* get vnode attributes from server */ 5414bff34e3Sthurlow va.va_mask = AT_SIZE | AT_MTIME; 5424bff34e3Sthurlow if (error = smbfsgetattr(vp, &va, cr)) 5434bff34e3Sthurlow goto out; 5444bff34e3Sthurlow 5454bff34e3Sthurlow /* should probably update mtime with mtime from server here */ 5464bff34e3Sthurlow 5474bff34e3Sthurlow /* 5484bff34e3Sthurlow * Darwin had a loop here that handled paging stuff. 5494bff34e3Sthurlow * Solaris does paging differently, so no loop needed. 5504bff34e3Sthurlow */ 5514bff34e3Sthurlow error = smbfs_readvnode(vp, uiop, cr, &va); 5524bff34e3Sthurlow 5534bff34e3Sthurlow out: 5544bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 5554bff34e3Sthurlow return (error); 5564bff34e3Sthurlow 5574bff34e3Sthurlow } 5584bff34e3Sthurlow 5594bff34e3Sthurlow 5604bff34e3Sthurlow /* ARGSUSED */ 5614bff34e3Sthurlow static int 5624bff34e3Sthurlow smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 5634bff34e3Sthurlow caller_context_t *ct) 5644bff34e3Sthurlow { 5654bff34e3Sthurlow int error; 5664bff34e3Sthurlow smbmntinfo_t *smi; 5674bff34e3Sthurlow smbnode_t *np; 5684bff34e3Sthurlow int timo = SMBWRTTIMO; 5694bff34e3Sthurlow 5704bff34e3Sthurlow np = VTOSMB(vp); 5714bff34e3Sthurlow smi = VTOSMI(vp); 5724bff34e3Sthurlow 5734bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 5744bff34e3Sthurlow return (EIO); 5754bff34e3Sthurlow 5764bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 5774bff34e3Sthurlow return (EIO); 5784bff34e3Sthurlow 5794bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER)); 5804bff34e3Sthurlow 5814bff34e3Sthurlow if (vp->v_type != VREG) 5824bff34e3Sthurlow return (EISDIR); 5834bff34e3Sthurlow 5844bff34e3Sthurlow if (uiop->uio_resid == 0) 5854bff34e3Sthurlow return (0); 5864bff34e3Sthurlow 5874bff34e3Sthurlow /* Shared lock for n_fid use in smbfs_writevnode */ 5884bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 5894bff34e3Sthurlow return (EINTR); 5904bff34e3Sthurlow 5914bff34e3Sthurlow 5924bff34e3Sthurlow /* 5934bff34e3Sthurlow * Darwin had a loop here that handled paging stuff. 5944bff34e3Sthurlow * Solaris does paging differently, so no loop needed. 5954bff34e3Sthurlow */ 5964bff34e3Sthurlow error = smbfs_writevnode(vp, uiop, cr, ioflag, timo); 5974bff34e3Sthurlow 5984bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 5994bff34e3Sthurlow return (error); 6004bff34e3Sthurlow 6014bff34e3Sthurlow } 6024bff34e3Sthurlow 6034bff34e3Sthurlow 604*7568150aSgwr /* ARGSUSED */ 605*7568150aSgwr static int 606*7568150aSgwr smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, 607*7568150aSgwr cred_t *cr, int *rvalp, caller_context_t *ct) 608*7568150aSgwr { 609*7568150aSgwr int error; 610*7568150aSgwr smbmntinfo_t *smi; 611*7568150aSgwr 612*7568150aSgwr smi = VTOSMI(vp); 613*7568150aSgwr 614*7568150aSgwr if (curproc->p_zone != smi->smi_zone) 615*7568150aSgwr return (EIO); 616*7568150aSgwr 617*7568150aSgwr if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 618*7568150aSgwr return (EIO); 619*7568150aSgwr 620*7568150aSgwr switch (cmd) { 621*7568150aSgwr /* First three from ZFS. XXX - need these? */ 622*7568150aSgwr 623*7568150aSgwr case _FIOFFS: 624*7568150aSgwr error = smbfs_fsync(vp, 0, cr, ct); 625*7568150aSgwr break; 626*7568150aSgwr 627*7568150aSgwr /* 628*7568150aSgwr * The following two ioctls are used by bfu. 629*7568150aSgwr * Silently ignore to avoid bfu errors. 630*7568150aSgwr */ 631*7568150aSgwr case _FIOGDIO: 632*7568150aSgwr case _FIOSDIO: 633*7568150aSgwr error = 0; 634*7568150aSgwr break; 635*7568150aSgwr 636*7568150aSgwr #ifdef NOT_YET /* XXX - from the NFS code. */ 637*7568150aSgwr case _FIODIRECTIO: 638*7568150aSgwr error = smbfs_directio(vp, (int)arg, cr); 639*7568150aSgwr #endif 640*7568150aSgwr 641*7568150aSgwr /* 642*7568150aSgwr * Allow get/set with "raw" security descriptor (SD) data. 643*7568150aSgwr * Useful for testing, diagnosing idmap problems, etc. 644*7568150aSgwr */ 645*7568150aSgwr case SMBFSIO_GETSD: 646*7568150aSgwr error = smbfs_ioc_getsd(vp, arg, flag, cr); 647*7568150aSgwr break; 648*7568150aSgwr 649*7568150aSgwr case SMBFSIO_SETSD: 650*7568150aSgwr error = smbfs_ioc_setsd(vp, arg, flag, cr); 651*7568150aSgwr break; 652*7568150aSgwr 653*7568150aSgwr default: 654*7568150aSgwr error = ENOTTY; 655*7568150aSgwr break; 656*7568150aSgwr } 657*7568150aSgwr 658*7568150aSgwr return (error); 659*7568150aSgwr } 660*7568150aSgwr 661*7568150aSgwr 6624bff34e3Sthurlow /* 6634bff34e3Sthurlow * Return either cached or remote attributes. If get remote attr 6644bff34e3Sthurlow * use them to check and invalidate caches, then cache the new attributes. 6654bff34e3Sthurlow * 6664bff34e3Sthurlow * XXX 6674bff34e3Sthurlow * This op should eventually support PSARC 2007/315, Extensible Attribute 6684bff34e3Sthurlow * Interfaces, for richer metadata. 6694bff34e3Sthurlow */ 6704bff34e3Sthurlow /* ARGSUSED */ 6714bff34e3Sthurlow static int 6724bff34e3Sthurlow smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 6734bff34e3Sthurlow caller_context_t *ct) 6744bff34e3Sthurlow { 6754bff34e3Sthurlow smbnode_t *np; 6764bff34e3Sthurlow smbmntinfo_t *smi; 6774bff34e3Sthurlow 6784bff34e3Sthurlow smi = VTOSMI(vp); 6794bff34e3Sthurlow 6804bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 6814bff34e3Sthurlow return (EIO); 6824bff34e3Sthurlow 6834bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 6844bff34e3Sthurlow return (EIO); 6854bff34e3Sthurlow 6864bff34e3Sthurlow /* 6874bff34e3Sthurlow * If it has been specified that the return value will 6884bff34e3Sthurlow * just be used as a hint, and we are only being asked 6894bff34e3Sthurlow * for size, fsid or rdevid, then return the client's 6904bff34e3Sthurlow * notion of these values without checking to make sure 6914bff34e3Sthurlow * that the attribute cache is up to date. 6924bff34e3Sthurlow * The whole point is to avoid an over the wire GETATTR 6934bff34e3Sthurlow * call. 6944bff34e3Sthurlow */ 6954bff34e3Sthurlow np = VTOSMB(vp); 6964bff34e3Sthurlow if (flags & ATTR_HINT) { 6974bff34e3Sthurlow if (vap->va_mask == 6984bff34e3Sthurlow (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) { 6994bff34e3Sthurlow mutex_enter(&np->r_statelock); 7004bff34e3Sthurlow if (vap->va_mask | AT_SIZE) 7014bff34e3Sthurlow vap->va_size = np->r_size; 7024bff34e3Sthurlow if (vap->va_mask | AT_FSID) 7034bff34e3Sthurlow vap->va_fsid = np->r_attr.va_fsid; 7044bff34e3Sthurlow if (vap->va_mask | AT_RDEV) 7054bff34e3Sthurlow vap->va_rdev = np->r_attr.va_rdev; 7064bff34e3Sthurlow mutex_exit(&np->r_statelock); 7074bff34e3Sthurlow return (0); 7084bff34e3Sthurlow } 7094bff34e3Sthurlow } 7104bff34e3Sthurlow 7114bff34e3Sthurlow 7124bff34e3Sthurlow return (smbfsgetattr(vp, vap, cr)); 7134bff34e3Sthurlow } 7144bff34e3Sthurlow 7154bff34e3Sthurlow /* 7164bff34e3Sthurlow * Mostly from Darwin smbfs_getattr() 7174bff34e3Sthurlow */ 7184bff34e3Sthurlow int 7194bff34e3Sthurlow smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr) 7204bff34e3Sthurlow { 7214bff34e3Sthurlow int error; 7224bff34e3Sthurlow smbnode_t *np; 7234bff34e3Sthurlow struct smb_cred scred; 7244bff34e3Sthurlow struct smbfattr fattr; 7254bff34e3Sthurlow 7264bff34e3Sthurlow ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); 7274bff34e3Sthurlow 7284bff34e3Sthurlow np = VTOSMB(vp); 7294bff34e3Sthurlow 7304bff34e3Sthurlow /* 7314bff34e3Sthurlow * If we've got cached attributes, we're done, otherwise go 7324bff34e3Sthurlow * to the server to get attributes, which will update the cache 7334bff34e3Sthurlow * in the process. 7344bff34e3Sthurlow * 7354bff34e3Sthurlow * This section from Darwin smbfs_getattr, 7364bff34e3Sthurlow * but then modified a lot. 7374bff34e3Sthurlow */ 7384bff34e3Sthurlow error = smbfs_attr_cachelookup(vp, vap); 7394bff34e3Sthurlow if (error != ENOENT) 7404bff34e3Sthurlow return (error); 7414bff34e3Sthurlow 7424bff34e3Sthurlow /* Shared lock for (possible) n_fid use. */ 7434bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 7444bff34e3Sthurlow return (EINTR); 7454bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 7464bff34e3Sthurlow 7474bff34e3Sthurlow error = smbfs_smb_getfattr(np, &fattr, &scred); 7484bff34e3Sthurlow 7494bff34e3Sthurlow smb_credrele(&scred); 7504bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 7514bff34e3Sthurlow 7524bff34e3Sthurlow if (!error) { 7534bff34e3Sthurlow smbfs_attr_cacheenter(vp, &fattr); 7544bff34e3Sthurlow error = smbfs_attr_cachelookup(vp, vap); 7554bff34e3Sthurlow } 7564bff34e3Sthurlow return (error); 7574bff34e3Sthurlow } 7584bff34e3Sthurlow 7594bff34e3Sthurlow /* 7604bff34e3Sthurlow * XXX 7614bff34e3Sthurlow * This op should eventually support PSARC 2007/315, Extensible Attribute 7624bff34e3Sthurlow * Interfaces, for richer metadata. 7634bff34e3Sthurlow */ 7644bff34e3Sthurlow /*ARGSUSED4*/ 7654bff34e3Sthurlow static int 7664bff34e3Sthurlow smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 7674bff34e3Sthurlow caller_context_t *ct) 7684bff34e3Sthurlow { 7694bff34e3Sthurlow int error; 7704bff34e3Sthurlow uint_t mask; 7714bff34e3Sthurlow struct vattr oldva; 7724bff34e3Sthurlow smbmntinfo_t *smi; 7734bff34e3Sthurlow 7744bff34e3Sthurlow smi = VTOSMI(vp); 7754bff34e3Sthurlow 7764bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 7774bff34e3Sthurlow return (EIO); 7784bff34e3Sthurlow 7794bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 7804bff34e3Sthurlow return (EIO); 7814bff34e3Sthurlow 7824bff34e3Sthurlow mask = vap->va_mask; 7834bff34e3Sthurlow if (mask & AT_NOSET) 7844bff34e3Sthurlow return (EINVAL); 7854bff34e3Sthurlow 7864bff34e3Sthurlow oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 7874bff34e3Sthurlow error = smbfsgetattr(vp, &oldva, cr); 7884bff34e3Sthurlow if (error) 7894bff34e3Sthurlow return (error); 7904bff34e3Sthurlow 7914bff34e3Sthurlow error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags, 7924bff34e3Sthurlow smbfs_accessx, vp); 7934bff34e3Sthurlow if (error) 7944bff34e3Sthurlow return (error); 7954bff34e3Sthurlow 7964bff34e3Sthurlow return (smbfssetattr(vp, vap, flags, cr)); 7974bff34e3Sthurlow } 7984bff34e3Sthurlow 7994bff34e3Sthurlow /* 8004bff34e3Sthurlow * Mostly from Darwin smbfs_setattr() 8014bff34e3Sthurlow * but then modified a lot. 8024bff34e3Sthurlow */ 8034bff34e3Sthurlow /* ARGSUSED */ 8044bff34e3Sthurlow static int 8054bff34e3Sthurlow smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) 8064bff34e3Sthurlow { 8074bff34e3Sthurlow int error = 0; 8084bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 8094bff34e3Sthurlow smbmntinfo_t *smi = VTOSMI(vp); 8104bff34e3Sthurlow uint_t mask = vap->va_mask; 8114bff34e3Sthurlow struct timespec *mtime, *atime; 8124bff34e3Sthurlow struct smb_cred scred; 8134bff34e3Sthurlow int cerror, modified = 0; 8144bff34e3Sthurlow unsigned short fid; 8154bff34e3Sthurlow int have_fid = 0; 8164bff34e3Sthurlow uint32_t rights = 0; 8174bff34e3Sthurlow 8184bff34e3Sthurlow ASSERT(curproc->p_zone == smi->smi_zone); 8194bff34e3Sthurlow 8204bff34e3Sthurlow /* 8214bff34e3Sthurlow * If our caller is trying to set multiple attributes, they 8224bff34e3Sthurlow * can make no assumption about what order they are done in. 8234bff34e3Sthurlow * Here we try to do them in order of decreasing likelihood 8244bff34e3Sthurlow * of failure, just to minimize the chance we'll wind up 8254bff34e3Sthurlow * with a partially complete request. 8264bff34e3Sthurlow */ 8274bff34e3Sthurlow 8284bff34e3Sthurlow /* Shared lock for (possible) n_fid use. */ 8294bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 8304bff34e3Sthurlow return (EINTR); 8314bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 8324bff34e3Sthurlow 8334bff34e3Sthurlow /* 8344bff34e3Sthurlow * Will we need an open handle for this setattr? 8354bff34e3Sthurlow * If so, what rights will we need? 8364bff34e3Sthurlow */ 8374bff34e3Sthurlow if (mask & (AT_ATIME | AT_MTIME)) { 8384bff34e3Sthurlow rights |= 8394bff34e3Sthurlow SA_RIGHT_FILE_WRITE_ATTRIBUTES | 8404bff34e3Sthurlow GENERIC_RIGHT_ALL_ACCESS | 8414bff34e3Sthurlow GENERIC_RIGHT_WRITE_ACCESS; 8424bff34e3Sthurlow } 8434bff34e3Sthurlow if (mask & AT_SIZE) { 8444bff34e3Sthurlow rights |= 8454bff34e3Sthurlow SA_RIGHT_FILE_WRITE_DATA | 8464bff34e3Sthurlow SA_RIGHT_FILE_APPEND_DATA; 8474bff34e3Sthurlow /* 8484bff34e3Sthurlow * Only SIZE requires a handle. 8494bff34e3Sthurlow * XXX May be more reliable to just 8504bff34e3Sthurlow * always get the file handle here. 8514bff34e3Sthurlow */ 8524bff34e3Sthurlow error = smbfs_smb_tmpopen(np, rights, &scred, &fid); 8534bff34e3Sthurlow if (error) { 8544bff34e3Sthurlow SMBVDEBUG("error %d opening %s\n", 8554bff34e3Sthurlow error, np->n_rpath); 8564bff34e3Sthurlow goto out; 8574bff34e3Sthurlow } 8584bff34e3Sthurlow have_fid = 1; 8594bff34e3Sthurlow } 8604bff34e3Sthurlow 8614bff34e3Sthurlow 8624bff34e3Sthurlow /* 8634bff34e3Sthurlow * If the server supports the UNIX extensions, right here is where 8644bff34e3Sthurlow * we'd support changes to uid, gid, mode, and possibly va_flags. 8654bff34e3Sthurlow * For now we claim to have made any such changes. 8664bff34e3Sthurlow */ 8674bff34e3Sthurlow 8684bff34e3Sthurlow if (mask & AT_SIZE) { 8694bff34e3Sthurlow /* 8704bff34e3Sthurlow * If the new file size is less than what the client sees as 8714bff34e3Sthurlow * the file size, then just change the size and invalidate 8724bff34e3Sthurlow * the pages. 8734bff34e3Sthurlow * I am commenting this code at present because the function 8744bff34e3Sthurlow * smbfs_putapage() is not yet implemented. 8754bff34e3Sthurlow */ 8764bff34e3Sthurlow 8774bff34e3Sthurlow /* 8784bff34e3Sthurlow * Set the file size to vap->va_size. 8794bff34e3Sthurlow */ 8804bff34e3Sthurlow ASSERT(have_fid); 8814bff34e3Sthurlow error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred); 8824bff34e3Sthurlow if (error) { 8834bff34e3Sthurlow SMBVDEBUG("setsize error %d file %s\n", 8844bff34e3Sthurlow error, np->n_rpath); 8854bff34e3Sthurlow } else { 8864bff34e3Sthurlow /* 8874bff34e3Sthurlow * Darwin had code here to zero-extend. 8884bff34e3Sthurlow * Tests indicate the server will zero-fill, 8894bff34e3Sthurlow * so looks like we don't need to do this. 8904bff34e3Sthurlow * Good thing, as this could take forever. 8914bff34e3Sthurlow */ 8924bff34e3Sthurlow mutex_enter(&np->r_statelock); 8934bff34e3Sthurlow np->r_size = vap->va_size; 8944bff34e3Sthurlow mutex_exit(&np->r_statelock); 8954bff34e3Sthurlow modified = 1; 8964bff34e3Sthurlow } 8974bff34e3Sthurlow } 8984bff34e3Sthurlow 8994bff34e3Sthurlow /* 9004bff34e3Sthurlow * XXX: When Solaris has create_time, set that too. 9014bff34e3Sthurlow * Note: create_time is different from ctime. 9024bff34e3Sthurlow */ 9034bff34e3Sthurlow mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0); 9044bff34e3Sthurlow atime = ((mask & AT_ATIME) ? &vap->va_atime : 0); 9054bff34e3Sthurlow 9064bff34e3Sthurlow if (mtime || atime) { 9074bff34e3Sthurlow /* 9084bff34e3Sthurlow * If file is opened with write-attributes capability, 9094bff34e3Sthurlow * we use handle-based calls. If not, we use path-based ones. 9104bff34e3Sthurlow */ 9114bff34e3Sthurlow if (have_fid) { 9124bff34e3Sthurlow error = smbfs_smb_setfattr(np, fid, 9134bff34e3Sthurlow np->n_dosattr, mtime, atime, &scred); 9144bff34e3Sthurlow } else { 9154bff34e3Sthurlow error = smbfs_smb_setpattr(np, 9164bff34e3Sthurlow np->n_dosattr, mtime, atime, &scred); 9174bff34e3Sthurlow } 9184bff34e3Sthurlow if (error) { 9194bff34e3Sthurlow SMBVDEBUG("set times error %d file %s\n", 9204bff34e3Sthurlow error, np->n_rpath); 9214bff34e3Sthurlow } else { 9224bff34e3Sthurlow /* XXX: set np->n_mtime, etc? */ 9234bff34e3Sthurlow modified = 1; 9244bff34e3Sthurlow } 9254bff34e3Sthurlow } 9264bff34e3Sthurlow 9274bff34e3Sthurlow out: 9284bff34e3Sthurlow if (modified) { 9294bff34e3Sthurlow /* 9304bff34e3Sthurlow * Invalidate attribute cache in case if server doesn't set 9314bff34e3Sthurlow * required attributes. 9324bff34e3Sthurlow */ 9334bff34e3Sthurlow smbfs_attr_cacheremove(np); 9344bff34e3Sthurlow /* 9354bff34e3Sthurlow * XXX Darwin called _getattr here to 9364bff34e3Sthurlow * update the mtime. Should we? 9374bff34e3Sthurlow */ 9384bff34e3Sthurlow } 9394bff34e3Sthurlow 9404bff34e3Sthurlow if (have_fid) { 9414bff34e3Sthurlow cerror = smbfs_smb_tmpclose(np, fid, &scred); 9424bff34e3Sthurlow if (cerror) 9434bff34e3Sthurlow SMBERROR("error %d closing %s\n", 9444bff34e3Sthurlow cerror, np->n_rpath); 9454bff34e3Sthurlow } 9464bff34e3Sthurlow 9474bff34e3Sthurlow smb_credrele(&scred); 9484bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 9494bff34e3Sthurlow 9504bff34e3Sthurlow return (error); 9514bff34e3Sthurlow } 9524bff34e3Sthurlow 9534bff34e3Sthurlow /* 9544bff34e3Sthurlow * smbfs_access_rwx() 9554bff34e3Sthurlow * Common function for smbfs_access, etc. 9564bff34e3Sthurlow * 9574bff34e3Sthurlow * The security model implemented by the FS is unusual 9584bff34e3Sthurlow * due to our "single user mounts" restriction. 9594bff34e3Sthurlow * 9604bff34e3Sthurlow * All access under a given mount point uses the CIFS 9614bff34e3Sthurlow * credentials established by the owner of the mount. 9624bff34e3Sthurlow * The Unix uid/gid/mode information is not (easily) 9634bff34e3Sthurlow * provided by CIFS, and is instead fabricated using 9644bff34e3Sthurlow * settings held in the mount structure. 9654bff34e3Sthurlow * 9664bff34e3Sthurlow * Most access checking is handled by the CIFS server, 9674bff34e3Sthurlow * but we need sufficient Unix access checks here to 9684bff34e3Sthurlow * prevent other local Unix users from having access 9694bff34e3Sthurlow * to objects under this mount that the uid/gid/mode 9704bff34e3Sthurlow * settings in the mount would not allow. 9714bff34e3Sthurlow * 9724bff34e3Sthurlow * With this model, there is a case where we need the 9734bff34e3Sthurlow * ability to do an access check before we have the 9744bff34e3Sthurlow * vnode for an object. This function takes advantage 9754bff34e3Sthurlow * of the fact that the uid/gid/mode is per mount, and 9764bff34e3Sthurlow * avoids the need for a vnode. 9774bff34e3Sthurlow * 9784bff34e3Sthurlow * We still (sort of) need a vnode when we call 9794bff34e3Sthurlow * secpolicy_vnode_access, but that only uses 9804bff34e3Sthurlow * the vtype field, so we can use a pair of fake 9814bff34e3Sthurlow * vnodes that have only v_type filled in. 9824bff34e3Sthurlow * 9834bff34e3Sthurlow * XXX: Later, add a new secpolicy_vtype_access() 9844bff34e3Sthurlow * that takes the vtype instead of a vnode, and 9854bff34e3Sthurlow * get rid of the tmpl_vxxx fake vnodes below. 9864bff34e3Sthurlow */ 9874bff34e3Sthurlow static int 9884bff34e3Sthurlow smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) 9894bff34e3Sthurlow { 9904bff34e3Sthurlow /* See the secpolicy call below. */ 9914bff34e3Sthurlow static const vnode_t tmpl_vdir = { .v_type = VDIR }; 9924bff34e3Sthurlow static const vnode_t tmpl_vreg = { .v_type = VREG }; 9934bff34e3Sthurlow vattr_t va; 9944bff34e3Sthurlow vnode_t *tvp; 9954bff34e3Sthurlow struct smbmntinfo *smi = VFTOSMI(vfsp); 9964bff34e3Sthurlow int shift = 0; 9974bff34e3Sthurlow 9984bff34e3Sthurlow /* 9994bff34e3Sthurlow * Build our (fabricated) vnode attributes. 10004bff34e3Sthurlow * XXX: Could make these templates in the 10014bff34e3Sthurlow * per-mount struct and use them here. 10024bff34e3Sthurlow */ 10034bff34e3Sthurlow bzero(&va, sizeof (va)); 10044bff34e3Sthurlow va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 10054bff34e3Sthurlow va.va_type = vtype; 10064bff34e3Sthurlow va.va_mode = (vtype == VDIR) ? 10074bff34e3Sthurlow smi->smi_args.dir_mode : 10084bff34e3Sthurlow smi->smi_args.file_mode; 10094bff34e3Sthurlow va.va_uid = smi->smi_args.uid; 10104bff34e3Sthurlow va.va_gid = smi->smi_args.gid; 10114bff34e3Sthurlow 10124bff34e3Sthurlow /* 10134bff34e3Sthurlow * Disallow write attempts on read-only file systems, 10144bff34e3Sthurlow * unless the file is a device or fifo node. Note: 10154bff34e3Sthurlow * Inline vn_is_readonly and IS_DEVVP here because 10164bff34e3Sthurlow * we may not have a vnode ptr. Original expr. was: 10174bff34e3Sthurlow * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp)) 10184bff34e3Sthurlow */ 10194bff34e3Sthurlow if ((mode & VWRITE) && 10204bff34e3Sthurlow (vfsp->vfs_flag & VFS_RDONLY) && 10214bff34e3Sthurlow !(vtype == VCHR || vtype == VBLK || vtype == VFIFO)) 10224bff34e3Sthurlow return (EROFS); 10234bff34e3Sthurlow 10244bff34e3Sthurlow /* 10254bff34e3Sthurlow * Disallow attempts to access mandatory lock files. 10264bff34e3Sthurlow * Similarly, expand MANDLOCK here. 10274bff34e3Sthurlow * XXX: not sure we need this. 10284bff34e3Sthurlow */ 10294bff34e3Sthurlow if ((mode & (VWRITE | VREAD | VEXEC)) && 10304bff34e3Sthurlow va.va_type == VREG && MANDMODE(va.va_mode)) 10314bff34e3Sthurlow return (EACCES); 10324bff34e3Sthurlow 10334bff34e3Sthurlow /* 10344bff34e3Sthurlow * Access check is based on only 10354bff34e3Sthurlow * one of owner, group, public. 10364bff34e3Sthurlow * If not owner, then check group. 10374bff34e3Sthurlow * If not a member of the group, 10384bff34e3Sthurlow * then check public access. 10394bff34e3Sthurlow */ 10404bff34e3Sthurlow if (crgetuid(cr) != va.va_uid) { 10414bff34e3Sthurlow shift += 3; 10424bff34e3Sthurlow if (!groupmember(va.va_gid, cr)) 10434bff34e3Sthurlow shift += 3; 10444bff34e3Sthurlow } 10454bff34e3Sthurlow mode &= ~(va.va_mode << shift); 10464bff34e3Sthurlow if (mode == 0) 10474bff34e3Sthurlow return (0); 10484bff34e3Sthurlow 10494bff34e3Sthurlow /* 10504bff34e3Sthurlow * We need a vnode for secpolicy_vnode_access, 10514bff34e3Sthurlow * but the only thing it looks at is v_type, 10524bff34e3Sthurlow * so pass one of the templates above. 10534bff34e3Sthurlow */ 10544bff34e3Sthurlow tvp = (va.va_type == VDIR) ? 10554bff34e3Sthurlow (vnode_t *)&tmpl_vdir : 10564bff34e3Sthurlow (vnode_t *)&tmpl_vreg; 10574bff34e3Sthurlow return (secpolicy_vnode_access(cr, tvp, va.va_uid, mode)); 10584bff34e3Sthurlow } 10594bff34e3Sthurlow 10604bff34e3Sthurlow /* 10614bff34e3Sthurlow * See smbfs_setattr 10624bff34e3Sthurlow */ 10634bff34e3Sthurlow static int 10644bff34e3Sthurlow smbfs_accessx(void *arg, int mode, cred_t *cr) 10654bff34e3Sthurlow { 10664bff34e3Sthurlow vnode_t *vp = arg; 10674bff34e3Sthurlow /* 10684bff34e3Sthurlow * Note: The caller has checked the current zone, 10694bff34e3Sthurlow * the SMI_DEAD and VFS_UNMOUNTED flags, etc. 10704bff34e3Sthurlow */ 10714bff34e3Sthurlow return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr)); 10724bff34e3Sthurlow } 10734bff34e3Sthurlow 10744bff34e3Sthurlow /* 10754bff34e3Sthurlow * XXX 10764bff34e3Sthurlow * This op should support PSARC 2007/403, Modified Access Checks for CIFS 10774bff34e3Sthurlow */ 10784bff34e3Sthurlow /* ARGSUSED */ 10794bff34e3Sthurlow static int 10804bff34e3Sthurlow smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) 10814bff34e3Sthurlow { 10824bff34e3Sthurlow vfs_t *vfsp; 10834bff34e3Sthurlow smbmntinfo_t *smi; 10844bff34e3Sthurlow 10854bff34e3Sthurlow vfsp = vp->v_vfsp; 10864bff34e3Sthurlow smi = VFTOSMI(vfsp); 10874bff34e3Sthurlow 10884bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 10894bff34e3Sthurlow return (EIO); 10904bff34e3Sthurlow 10914bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 10924bff34e3Sthurlow return (EIO); 10934bff34e3Sthurlow 10944bff34e3Sthurlow return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr)); 10954bff34e3Sthurlow } 10964bff34e3Sthurlow 10974bff34e3Sthurlow 10984bff34e3Sthurlow /* 10994bff34e3Sthurlow * Flush local dirty pages to stable storage on the server. 11004bff34e3Sthurlow * 11014bff34e3Sthurlow * If FNODSYNC is specified, then there is nothing to do because 11024bff34e3Sthurlow * metadata changes are not cached on the client before being 11034bff34e3Sthurlow * sent to the server. 11044bff34e3Sthurlow * 11054bff34e3Sthurlow * Currently, this is a no-op since we don't cache data, either. 11064bff34e3Sthurlow */ 11074bff34e3Sthurlow /* ARGSUSED */ 11084bff34e3Sthurlow static int 11094bff34e3Sthurlow smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 11104bff34e3Sthurlow { 11114bff34e3Sthurlow int error = 0; 11124bff34e3Sthurlow smbmntinfo_t *smi; 11134bff34e3Sthurlow 11144bff34e3Sthurlow smi = VTOSMI(vp); 11154bff34e3Sthurlow 11164bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 11174bff34e3Sthurlow return (EIO); 11184bff34e3Sthurlow 11194bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 11204bff34e3Sthurlow return (EIO); 11214bff34e3Sthurlow 11224bff34e3Sthurlow if ((syncflag & FNODSYNC) || IS_SWAPVP(vp)) 11234bff34e3Sthurlow return (0); 11244bff34e3Sthurlow 11254bff34e3Sthurlow return (error); 11264bff34e3Sthurlow } 11274bff34e3Sthurlow 11284bff34e3Sthurlow /* 11294bff34e3Sthurlow * Last reference to vnode went away. 11304bff34e3Sthurlow */ 11314bff34e3Sthurlow /* ARGSUSED */ 11324bff34e3Sthurlow static void 11334bff34e3Sthurlow smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 11344bff34e3Sthurlow { 11354bff34e3Sthurlow smbnode_t *np; 11364bff34e3Sthurlow 11374bff34e3Sthurlow /* 11384bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 11394bff34e3Sthurlow * as we want to do cleanup, etc. 11404bff34e3Sthurlow * See also pcfs_inactive 11414bff34e3Sthurlow */ 11424bff34e3Sthurlow 11434bff34e3Sthurlow np = VTOSMB(vp); 11444bff34e3Sthurlow 11454bff34e3Sthurlow /* 11464bff34e3Sthurlow * If this is coming from the wrong zone, we let someone in the right 11474bff34e3Sthurlow * zone take care of it asynchronously. We can get here due to 11484bff34e3Sthurlow * VN_RELE() being called from pageout() or fsflush(). This call may 11494bff34e3Sthurlow * potentially turn into an expensive no-op if, for instance, v_count 11504bff34e3Sthurlow * gets incremented in the meantime, but it's still correct. 11514bff34e3Sthurlow */ 11524bff34e3Sthurlow 11534bff34e3Sthurlow /* 11544bff34e3Sthurlow * Some paranoia from the Darwin code: 11554bff34e3Sthurlow * Make sure the FID was closed. 11564bff34e3Sthurlow * If we see this, it's a bug! 11574bff34e3Sthurlow * 11584bff34e3Sthurlow * No rw_enter here, as this should be the 11594bff34e3Sthurlow * last ref, and we're just looking... 11604bff34e3Sthurlow */ 11614bff34e3Sthurlow if (np->n_fidrefs > 0) { 11624bff34e3Sthurlow SMBVDEBUG("opencount %d fid %d file %s\n", 11634bff34e3Sthurlow np->n_fidrefs, np->n_fid, np->n_rpath); 11644bff34e3Sthurlow } 11654bff34e3Sthurlow if (np->n_dirrefs > 0) { 11664bff34e3Sthurlow uint_t fid = (np->n_dirseq) ? 11674bff34e3Sthurlow np->n_dirseq->f_Sid : 0; 11684bff34e3Sthurlow SMBVDEBUG("opencount %d fid %d dir %s\n", 11694bff34e3Sthurlow np->n_dirrefs, fid, np->n_rpath); 11704bff34e3Sthurlow } 11714bff34e3Sthurlow 11724bff34e3Sthurlow smb_addfree(np); 11734bff34e3Sthurlow } 11744bff34e3Sthurlow 11754bff34e3Sthurlow /* 11764bff34e3Sthurlow * Remote file system operations having to do with directory manipulation. 11774bff34e3Sthurlow */ 11784bff34e3Sthurlow /* ARGSUSED */ 11794bff34e3Sthurlow static int 11804bff34e3Sthurlow smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, 11814bff34e3Sthurlow int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 11824bff34e3Sthurlow int *direntflags, pathname_t *realpnp) 11834bff34e3Sthurlow { 11844bff34e3Sthurlow int error; 11854bff34e3Sthurlow smbnode_t *dnp; 11864bff34e3Sthurlow smbmntinfo_t *smi; 11874bff34e3Sthurlow 11884bff34e3Sthurlow smi = VTOSMI(dvp); 11894bff34e3Sthurlow 11904bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 11914bff34e3Sthurlow return (EPERM); 11924bff34e3Sthurlow 11934bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 11944bff34e3Sthurlow return (EIO); 11954bff34e3Sthurlow 11964bff34e3Sthurlow dnp = VTOSMB(dvp); 11974bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) { 11984bff34e3Sthurlow error = EINTR; 11994bff34e3Sthurlow goto out; 12004bff34e3Sthurlow } 12014bff34e3Sthurlow 12024bff34e3Sthurlow error = smbfslookup(dvp, nm, vpp, cr, 1, ct); 12034bff34e3Sthurlow 12044bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 12054bff34e3Sthurlow 12064bff34e3Sthurlow out: 12074bff34e3Sthurlow return (error); 12084bff34e3Sthurlow } 12094bff34e3Sthurlow 12104bff34e3Sthurlow /* ARGSUSED */ 12114bff34e3Sthurlow static int 12124bff34e3Sthurlow smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, 12134bff34e3Sthurlow caller_context_t *ct) 12144bff34e3Sthurlow { 12154bff34e3Sthurlow int error; 12164bff34e3Sthurlow int supplen; /* supported length */ 12174bff34e3Sthurlow vnode_t *vp; 12184bff34e3Sthurlow smbnode_t *dnp; 12194bff34e3Sthurlow smbmntinfo_t *smi; 12204bff34e3Sthurlow /* struct smb_vc *vcp; */ 12214bff34e3Sthurlow const char *name = (const char *)nm; 12224bff34e3Sthurlow int nmlen = strlen(nm); 12234bff34e3Sthurlow int rplen; 12244bff34e3Sthurlow struct smb_cred scred; 12254bff34e3Sthurlow struct smbfattr fa; 12264bff34e3Sthurlow 12274bff34e3Sthurlow smi = VTOSMI(dvp); 12284bff34e3Sthurlow dnp = VTOSMB(dvp); 12294bff34e3Sthurlow 12304bff34e3Sthurlow ASSERT(curproc->p_zone == smi->smi_zone); 12314bff34e3Sthurlow 12324bff34e3Sthurlow #ifdef NOT_YET 12334bff34e3Sthurlow vcp = SSTOVC(smi->smi_share); 12344bff34e3Sthurlow 12354bff34e3Sthurlow /* XXX: Should compute this once and store it in smbmntinfo_t */ 12364bff34e3Sthurlow supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12; 12374bff34e3Sthurlow #else 12384bff34e3Sthurlow supplen = 255; 12394bff34e3Sthurlow #endif 12404bff34e3Sthurlow 12414bff34e3Sthurlow /* 12424bff34e3Sthurlow * RWlock must be held, either reader or writer. 12434bff34e3Sthurlow * XXX: Can we check without looking directly 12444bff34e3Sthurlow * inside the struct smbfs_rwlock_t? 12454bff34e3Sthurlow */ 12464bff34e3Sthurlow ASSERT(dnp->r_rwlock.count != 0); 12474bff34e3Sthurlow 12484bff34e3Sthurlow /* 12494bff34e3Sthurlow * If lookup is for "", just return dvp. Don't need 12504bff34e3Sthurlow * to send it over the wire, look it up in the dnlc, 12514bff34e3Sthurlow * or perform any access checks. 12524bff34e3Sthurlow */ 12534bff34e3Sthurlow if (nmlen == 0) { 12544bff34e3Sthurlow VN_HOLD(dvp); 12554bff34e3Sthurlow *vpp = dvp; 12564bff34e3Sthurlow return (0); 12574bff34e3Sthurlow } 12584bff34e3Sthurlow 12594bff34e3Sthurlow /* if the name is longer that what is supported, return an error */ 12604bff34e3Sthurlow if (nmlen > supplen) 12614bff34e3Sthurlow return (ENAMETOOLONG); 12624bff34e3Sthurlow 12634bff34e3Sthurlow /* 12644bff34e3Sthurlow * Avoid surprises with characters that are 12654bff34e3Sthurlow * illegal in Windows file names. 12664bff34e3Sthurlow * Todo: CATIA mappings XXX 12674bff34e3Sthurlow */ 12684bff34e3Sthurlow if (strpbrk(nm, illegal_chars)) 12694bff34e3Sthurlow return (EINVAL); 12704bff34e3Sthurlow 12714bff34e3Sthurlow /* if the dvp is not a directory, return an error */ 12724bff34e3Sthurlow if (dvp->v_type != VDIR) 12734bff34e3Sthurlow return (ENOTDIR); 12744bff34e3Sthurlow 12754bff34e3Sthurlow /* Need search permission in the directory. */ 12764bff34e3Sthurlow error = smbfs_access(dvp, VEXEC, 0, cr, ct); 12774bff34e3Sthurlow if (error) 12784bff34e3Sthurlow return (error); 12794bff34e3Sthurlow 12804bff34e3Sthurlow /* 12814bff34e3Sthurlow * If lookup is for ".", just return dvp. Don't need 12824bff34e3Sthurlow * to send it over the wire or look it up in the dnlc, 12834bff34e3Sthurlow * just need to check access (done above). 12844bff34e3Sthurlow */ 12854bff34e3Sthurlow if (nmlen == 1 && name[0] == '.') { 12864bff34e3Sthurlow VN_HOLD(dvp); 12874bff34e3Sthurlow *vpp = dvp; 12884bff34e3Sthurlow return (0); 12894bff34e3Sthurlow } 12904bff34e3Sthurlow 12914bff34e3Sthurlow #ifdef NOT_YET 12924bff34e3Sthurlow if (dnlc) { 12934bff34e3Sthurlow /* 12944bff34e3Sthurlow * NOTE: search the dnlc here 12954bff34e3Sthurlow */ 12964bff34e3Sthurlow } 12974bff34e3Sthurlow #endif 12984bff34e3Sthurlow 12994bff34e3Sthurlow /* 13004bff34e3Sthurlow * Handle lookup of ".." which is quite tricky, 13014bff34e3Sthurlow * because the protocol gives us little help. 13024bff34e3Sthurlow * 13034bff34e3Sthurlow * We keep full pathnames (as seen on the server) 13044bff34e3Sthurlow * so we can just trim off the last component to 13054bff34e3Sthurlow * get the full pathname of the parent. Note: 13064bff34e3Sthurlow * We don't actually copy and modify, but just 13074bff34e3Sthurlow * compute the trimmed length and pass that with 13084bff34e3Sthurlow * the current dir path (not null terminated). 13094bff34e3Sthurlow * 13104bff34e3Sthurlow * We don't go over-the-wire to get attributes 13114bff34e3Sthurlow * for ".." because we know it's a directory, 13124bff34e3Sthurlow * and we can just leave the rest "stale" 13134bff34e3Sthurlow * until someone does a getattr. 13144bff34e3Sthurlow */ 13154bff34e3Sthurlow if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 13164bff34e3Sthurlow if (dvp->v_flag & VROOT) { 13174bff34e3Sthurlow /* 13184bff34e3Sthurlow * Already at the root. This can happen 13194bff34e3Sthurlow * with directory listings at the root, 13204bff34e3Sthurlow * which lookup "." and ".." to get the 13214bff34e3Sthurlow * inode numbers. Let ".." be the same 13224bff34e3Sthurlow * as "." in the FS root. 13234bff34e3Sthurlow */ 13244bff34e3Sthurlow VN_HOLD(dvp); 13254bff34e3Sthurlow *vpp = dvp; 13264bff34e3Sthurlow return (0); 13274bff34e3Sthurlow } 13284bff34e3Sthurlow 13294bff34e3Sthurlow /* 13304bff34e3Sthurlow * Find the parent path length. 13314bff34e3Sthurlow */ 13324bff34e3Sthurlow rplen = dnp->n_rplen; 13334bff34e3Sthurlow ASSERT(rplen > 0); 13344bff34e3Sthurlow while (--rplen >= 0) { 13354bff34e3Sthurlow if (dnp->n_rpath[rplen] == '\\') 13364bff34e3Sthurlow break; 13374bff34e3Sthurlow } 13384bff34e3Sthurlow if (rplen == 0) { 13394bff34e3Sthurlow /* Found our way to the root. */ 13404bff34e3Sthurlow vp = SMBTOV(smi->smi_root); 13414bff34e3Sthurlow VN_HOLD(vp); 13424bff34e3Sthurlow *vpp = vp; 13434bff34e3Sthurlow return (0); 13444bff34e3Sthurlow } 13454bff34e3Sthurlow vp = smbfs_make_node(dvp->v_vfsp, 13464bff34e3Sthurlow dnp->n_rpath, rplen, 13474bff34e3Sthurlow NULL, 0, NULL); 13484bff34e3Sthurlow if (vp == NULL) { 13494bff34e3Sthurlow return (ENOENT); 13504bff34e3Sthurlow } 13514bff34e3Sthurlow vp->v_type = VDIR; 13524bff34e3Sthurlow 13534bff34e3Sthurlow /* Success! */ 13544bff34e3Sthurlow *vpp = vp; 13554bff34e3Sthurlow return (0); 13564bff34e3Sthurlow } 13574bff34e3Sthurlow 13584bff34e3Sthurlow /* 13594bff34e3Sthurlow * Normal lookup of a child node. 13604bff34e3Sthurlow * Note we handled "." and ".." above. 13614bff34e3Sthurlow * 13624bff34e3Sthurlow * First, go over-the-wire to get the 13634bff34e3Sthurlow * node type (and attributes). 13644bff34e3Sthurlow */ 13654bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 13664bff34e3Sthurlow /* Note: this can allocate a new "name" */ 13674bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred); 13684bff34e3Sthurlow smb_credrele(&scred); 13694bff34e3Sthurlow if (error) 13704bff34e3Sthurlow goto out; 13714bff34e3Sthurlow 13724bff34e3Sthurlow /* 13734bff34e3Sthurlow * Find or create the node. 13744bff34e3Sthurlow */ 13754bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fa, &vp); 13764bff34e3Sthurlow if (error) 13774bff34e3Sthurlow goto out; 13784bff34e3Sthurlow 13794bff34e3Sthurlow /* Success! */ 13804bff34e3Sthurlow *vpp = vp; 13814bff34e3Sthurlow 13824bff34e3Sthurlow out: 13834bff34e3Sthurlow /* smbfs_smb_lookup may have allocated name. */ 13844bff34e3Sthurlow if (name != nm) 13854bff34e3Sthurlow smbfs_name_free(name, nmlen); 13864bff34e3Sthurlow 13874bff34e3Sthurlow return (error); 13884bff34e3Sthurlow } 13894bff34e3Sthurlow 13904bff34e3Sthurlow /* 13914bff34e3Sthurlow * XXX 13924bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 13934bff34e3Sthurlow * it in order to create an ACL when an object is created. 13944bff34e3Sthurlow * 13954bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 13964bff34e3Sthurlow * lookups, per PSARC 2007/244. 13974bff34e3Sthurlow */ 13984bff34e3Sthurlow /* ARGSUSED */ 13994bff34e3Sthurlow static int 14004bff34e3Sthurlow smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, 14014bff34e3Sthurlow int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct, 14024bff34e3Sthurlow vsecattr_t *vsecp) 14034bff34e3Sthurlow { 14044bff34e3Sthurlow int error; 14054bff34e3Sthurlow int cerror; 14064bff34e3Sthurlow vfs_t *vfsp; 14074bff34e3Sthurlow vnode_t *vp; 14084bff34e3Sthurlow #ifdef NOT_YET 14094bff34e3Sthurlow smbnode_t *np; 14104bff34e3Sthurlow #endif 14114bff34e3Sthurlow smbnode_t *dnp; 14124bff34e3Sthurlow smbmntinfo_t *smi; 14134bff34e3Sthurlow struct vattr vattr; 14144bff34e3Sthurlow struct smbfattr fattr; 14154bff34e3Sthurlow struct smb_cred scred; 14164bff34e3Sthurlow const char *name = (const char *)nm; 14174bff34e3Sthurlow int nmlen = strlen(nm); 14184bff34e3Sthurlow uint32_t disp; 14194bff34e3Sthurlow uint16_t fid; 14204bff34e3Sthurlow 14214bff34e3Sthurlow vfsp = dvp->v_vfsp; 14224bff34e3Sthurlow smi = VFTOSMI(vfsp); 14234bff34e3Sthurlow dnp = VTOSMB(dvp); 14244bff34e3Sthurlow vp = NULL; 14254bff34e3Sthurlow 14264bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 14274bff34e3Sthurlow return (EPERM); 14284bff34e3Sthurlow 14294bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 14304bff34e3Sthurlow return (EIO); 14314bff34e3Sthurlow 14324bff34e3Sthurlow /* 14334bff34e3Sthurlow * Note: this may break mknod(2) calls to create a directory, 14344bff34e3Sthurlow * but that's obscure use. Some other filesystems do this. 14354bff34e3Sthurlow * XXX: Later, redirect VDIR type here to _mkdir. 14364bff34e3Sthurlow */ 14374bff34e3Sthurlow if (va->va_type != VREG) 14384bff34e3Sthurlow return (EINVAL); 14394bff34e3Sthurlow 14404bff34e3Sthurlow /* 14414bff34e3Sthurlow * If the pathname is "", just use dvp, no checks. 14424bff34e3Sthurlow * Do this outside of the rwlock (like zfs). 14434bff34e3Sthurlow */ 14444bff34e3Sthurlow if (nmlen == 0) { 14454bff34e3Sthurlow VN_HOLD(dvp); 14464bff34e3Sthurlow *vpp = dvp; 14474bff34e3Sthurlow return (0); 14484bff34e3Sthurlow } 14494bff34e3Sthurlow 14504bff34e3Sthurlow /* Don't allow "." or ".." through here. */ 14514bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 14524bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 14534bff34e3Sthurlow return (EISDIR); 14544bff34e3Sthurlow 14554bff34e3Sthurlow /* 14564bff34e3Sthurlow * We make a copy of the attributes because the caller does not 14574bff34e3Sthurlow * expect us to change what va points to. 14584bff34e3Sthurlow */ 14594bff34e3Sthurlow vattr = *va; 14604bff34e3Sthurlow 14614bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 14624bff34e3Sthurlow return (EINTR); 14634bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 14644bff34e3Sthurlow 14654bff34e3Sthurlow /* 14664bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 14674bff34e3Sthurlow * No use of any shared fid or fctx... 14684bff34e3Sthurlow */ 14694bff34e3Sthurlow 14704bff34e3Sthurlow /* 14714bff34e3Sthurlow * NFS needs to go over the wire, just to be sure whether the 14724bff34e3Sthurlow * file exists or not. Using the DNLC can be dangerous in 14734bff34e3Sthurlow * this case when making a decision regarding existence. 14744bff34e3Sthurlow * 14754bff34e3Sthurlow * The SMB protocol does NOT really need to go OTW here 14764bff34e3Sthurlow * thanks to the expressive NTCREATE disposition values. 14774bff34e3Sthurlow * Unfortunately, to do Unix access checks correctly, 14784bff34e3Sthurlow * we need to know if the object already exists. 14794bff34e3Sthurlow * When the object does not exist, we need VWRITE on 14804bff34e3Sthurlow * the directory. Note: smbfslookup() checks VEXEC. 14814bff34e3Sthurlow */ 14824bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 14834bff34e3Sthurlow if (error == 0) { 14844bff34e3Sthurlow /* 14854bff34e3Sthurlow * file already exists 14864bff34e3Sthurlow */ 14874bff34e3Sthurlow if (exclusive == EXCL) { 14884bff34e3Sthurlow error = EEXIST; 14894bff34e3Sthurlow goto out; 14904bff34e3Sthurlow } 14914bff34e3Sthurlow /* 14924bff34e3Sthurlow * Verify requested access. 14934bff34e3Sthurlow */ 14944bff34e3Sthurlow error = smbfs_access(vp, mode, 0, cr, ct); 14954bff34e3Sthurlow if (error) 14964bff34e3Sthurlow goto out; 14974bff34e3Sthurlow 14984bff34e3Sthurlow /* 14994bff34e3Sthurlow * Truncate (if requested). 15004bff34e3Sthurlow */ 15014bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) { 15024bff34e3Sthurlow vattr.va_mask = AT_SIZE; 15034bff34e3Sthurlow error = smbfssetattr(vp, &vattr, 0, cr); 15044bff34e3Sthurlow if (error) 15054bff34e3Sthurlow goto out; 15064bff34e3Sthurlow } 15074bff34e3Sthurlow /* Success! */ 15084bff34e3Sthurlow #ifdef NOT_YET 15094bff34e3Sthurlow vnevent_create(vp, ct); 15104bff34e3Sthurlow #endif 15114bff34e3Sthurlow *vpp = vp; 15124bff34e3Sthurlow goto out; 15134bff34e3Sthurlow } 15144bff34e3Sthurlow 15154bff34e3Sthurlow /* 15164bff34e3Sthurlow * The file did not exist. Need VWRITE in the directory. 15174bff34e3Sthurlow */ 15184bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 15194bff34e3Sthurlow if (error) 15204bff34e3Sthurlow goto out; 15214bff34e3Sthurlow 15224bff34e3Sthurlow /* 15234bff34e3Sthurlow * Now things get tricky. We also need to check the 15244bff34e3Sthurlow * requested open mode against the file we may create. 15254bff34e3Sthurlow * See comments at smbfs_access_rwx 15264bff34e3Sthurlow */ 15274bff34e3Sthurlow error = smbfs_access_rwx(vfsp, VREG, mode, cr); 15284bff34e3Sthurlow if (error) 15294bff34e3Sthurlow goto out; 15304bff34e3Sthurlow 15314bff34e3Sthurlow #ifdef NOT_YET 15324bff34e3Sthurlow /* remove the entry from the negative entry from the dnlc */ 15334bff34e3Sthurlow dnlc_remove(dvp, name); 15344bff34e3Sthurlow #endif 15354bff34e3Sthurlow 15364bff34e3Sthurlow /* 15374bff34e3Sthurlow * Now the code derived from Darwin, 15384bff34e3Sthurlow * but with greater use of NT_CREATE 15394bff34e3Sthurlow * disposition options. Much changed. 15404bff34e3Sthurlow * 15414bff34e3Sthurlow * Create (or open) a new child node. 15424bff34e3Sthurlow * Note we handled "." and ".." above. 15434bff34e3Sthurlow */ 15444bff34e3Sthurlow 15454bff34e3Sthurlow if (exclusive == EXCL) 15464bff34e3Sthurlow disp = NTCREATEX_DISP_CREATE; 15474bff34e3Sthurlow else { 15484bff34e3Sthurlow /* Truncate regular files if requested. */ 15494bff34e3Sthurlow if ((va->va_type == VREG) && 15504bff34e3Sthurlow (va->va_mask & AT_SIZE) && 15514bff34e3Sthurlow (va->va_size == 0)) 15524bff34e3Sthurlow disp = NTCREATEX_DISP_OVERWRITE_IF; 15534bff34e3Sthurlow else 15544bff34e3Sthurlow disp = NTCREATEX_DISP_OPEN_IF; 15554bff34e3Sthurlow } 15564bff34e3Sthurlow error = smbfs_smb_create(dnp, name, nmlen, &scred, &fid, disp, 0); 15574bff34e3Sthurlow if (error) 15584bff34e3Sthurlow goto out; 15594bff34e3Sthurlow 15604bff34e3Sthurlow /* 15614bff34e3Sthurlow * XXX: Missing some code here to deal with 15624bff34e3Sthurlow * the case where we opened an existing file, 15634bff34e3Sthurlow * it's size is larger than 32-bits, and we're 15644bff34e3Sthurlow * setting the size from a process that's not 15654bff34e3Sthurlow * aware of large file offsets. i.e. 15664bff34e3Sthurlow * from the NFS3 code: 15674bff34e3Sthurlow */ 15684bff34e3Sthurlow #if NOT_YET /* XXX */ 15694bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && 15704bff34e3Sthurlow vp->v_type == VREG) { 15714bff34e3Sthurlow np = VTOSMB(vp); 15724bff34e3Sthurlow /* 15734bff34e3Sthurlow * Check here for large file handled 15744bff34e3Sthurlow * by LF-unaware process (as 15754bff34e3Sthurlow * ufs_create() does) 15764bff34e3Sthurlow */ 15774bff34e3Sthurlow if (!(lfaware & FOFFMAX)) { 15784bff34e3Sthurlow mutex_enter(&np->r_statelock); 15794bff34e3Sthurlow if (np->r_size > MAXOFF32_T) 15804bff34e3Sthurlow error = EOVERFLOW; 15814bff34e3Sthurlow mutex_exit(&np->r_statelock); 15824bff34e3Sthurlow } 15834bff34e3Sthurlow if (!error) { 15844bff34e3Sthurlow vattr.va_mask = AT_SIZE; 15854bff34e3Sthurlow error = smbfssetattr(vp, 15864bff34e3Sthurlow &vattr, 0, cr); 15874bff34e3Sthurlow } 15884bff34e3Sthurlow } 15894bff34e3Sthurlow #endif /* XXX */ 15904bff34e3Sthurlow /* 15914bff34e3Sthurlow * Should use the fid to get/set the size 15924bff34e3Sthurlow * while we have it opened here. See above. 15934bff34e3Sthurlow */ 15944bff34e3Sthurlow 15954bff34e3Sthurlow cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred); 15964bff34e3Sthurlow if (cerror) 15974bff34e3Sthurlow SMBERROR("error %d closing %s\\%s\n", 15984bff34e3Sthurlow cerror, dnp->n_rpath, name); 15994bff34e3Sthurlow 16004bff34e3Sthurlow /* 16014bff34e3Sthurlow * In the open case, the name may differ a little 16024bff34e3Sthurlow * from what we passed to create (case, etc.) 16034bff34e3Sthurlow * so call lookup to get the (opened) name. 16044bff34e3Sthurlow * 16054bff34e3Sthurlow * XXX: Could avoid this extra lookup if the 16064bff34e3Sthurlow * "createact" result from NT_CREATE says we 16074bff34e3Sthurlow * created the object. 16084bff34e3Sthurlow */ 16094bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 16104bff34e3Sthurlow if (error) 16114bff34e3Sthurlow goto out; 16124bff34e3Sthurlow 16134bff34e3Sthurlow /* update attr and directory cache */ 16144bff34e3Sthurlow smbfs_attr_touchdir(dnp); 16154bff34e3Sthurlow 16164bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 16174bff34e3Sthurlow if (error) 16184bff34e3Sthurlow goto out; 16194bff34e3Sthurlow 16204bff34e3Sthurlow #ifdef NOT_YET 16214bff34e3Sthurlow dnlc_update(dvp, name, vp); 16224bff34e3Sthurlow /* XXX invalidate pages if we truncated? */ 16234bff34e3Sthurlow #endif 16244bff34e3Sthurlow 16254bff34e3Sthurlow /* Success! */ 16264bff34e3Sthurlow *vpp = vp; 16274bff34e3Sthurlow error = 0; 16284bff34e3Sthurlow 16294bff34e3Sthurlow out: 16304bff34e3Sthurlow smb_credrele(&scred); 16314bff34e3Sthurlow if (name != nm) 16324bff34e3Sthurlow smbfs_name_free(name, nmlen); 16334bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 16344bff34e3Sthurlow return (error); 16354bff34e3Sthurlow } 16364bff34e3Sthurlow 16374bff34e3Sthurlow /* 16384bff34e3Sthurlow * XXX 16394bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 16404bff34e3Sthurlow * lookups, per PSARC 2007/244. 16414bff34e3Sthurlow */ 16424bff34e3Sthurlow /* ARGSUSED */ 16434bff34e3Sthurlow static int 16444bff34e3Sthurlow smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, 16454bff34e3Sthurlow int flags) 16464bff34e3Sthurlow { 16474bff34e3Sthurlow int error; 16484bff34e3Sthurlow vnode_t *vp; 16494bff34e3Sthurlow smbnode_t *np; 16504bff34e3Sthurlow smbnode_t *dnp; 16514bff34e3Sthurlow struct smb_cred scred; 16524bff34e3Sthurlow /* enum smbfsstat status; */ 16534bff34e3Sthurlow smbmntinfo_t *smi; 16544bff34e3Sthurlow 16554bff34e3Sthurlow smi = VTOSMI(dvp); 16564bff34e3Sthurlow 16574bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 16584bff34e3Sthurlow return (EPERM); 16594bff34e3Sthurlow 16604bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 16614bff34e3Sthurlow return (EIO); 16624bff34e3Sthurlow 16634bff34e3Sthurlow dnp = VTOSMB(dvp); 16644bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 16654bff34e3Sthurlow return (EINTR); 16664bff34e3Sthurlow 16674bff34e3Sthurlow /* 16684bff34e3Sthurlow * Verify access to the dirctory. 16694bff34e3Sthurlow */ 16704bff34e3Sthurlow error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct); 16714bff34e3Sthurlow if (error) 16724bff34e3Sthurlow goto out; 16734bff34e3Sthurlow 16744bff34e3Sthurlow /* 16754bff34e3Sthurlow * NOTE: the darwin code gets the "vp" passed in so it looks 16764bff34e3Sthurlow * like the "vp" has probably been "lookup"ed by the VFS layer. 16774bff34e3Sthurlow * It looks like we will need to lookup the vp to check the 16784bff34e3Sthurlow * caches and check if the object being deleted is a directory. 16794bff34e3Sthurlow */ 16804bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 16814bff34e3Sthurlow if (error) 16824bff34e3Sthurlow goto out; 16834bff34e3Sthurlow 16844bff34e3Sthurlow /* Never allow link/unlink directories on CIFS. */ 16854bff34e3Sthurlow if (vp->v_type == VDIR) { 16864bff34e3Sthurlow VN_RELE(vp); 16874bff34e3Sthurlow error = EPERM; 16884bff34e3Sthurlow goto out; 16894bff34e3Sthurlow } 16904bff34e3Sthurlow 16914bff34e3Sthurlow #ifdef NOT_YET 16924bff34e3Sthurlow /* 16934bff34e3Sthurlow * First just remove the entry from the name cache, as it 16944bff34e3Sthurlow * is most likely the only entry for this vp. 16954bff34e3Sthurlow */ 16964bff34e3Sthurlow dnlc_remove(dvp, nm); 16974bff34e3Sthurlow 16984bff34e3Sthurlow /* 16994bff34e3Sthurlow * If the file has a v_count > 1 then there may be more than one 17004bff34e3Sthurlow * entry in the name cache due multiple links or an open file, 17014bff34e3Sthurlow * but we don't have the real reference count so flush all 17024bff34e3Sthurlow * possible entries. 17034bff34e3Sthurlow */ 17044bff34e3Sthurlow if (vp->v_count > 1) 17054bff34e3Sthurlow dnlc_purge_vp(vp); 17064bff34e3Sthurlow #endif /* NOT_YET */ 17074bff34e3Sthurlow 17084bff34e3Sthurlow /* 17094bff34e3Sthurlow * Now we have the real reference count on the vnode 17104bff34e3Sthurlow */ 17114bff34e3Sthurlow np = VTOSMB(vp); 17124bff34e3Sthurlow mutex_enter(&np->r_statelock); 17134bff34e3Sthurlow if (vp->v_count > 1) { 17144bff34e3Sthurlow /* 17154bff34e3Sthurlow * NFS does a rename on remove here. 17164bff34e3Sthurlow * Probably not applicable for SMB. 17174bff34e3Sthurlow * Like Darwin, just return EBUSY. 17184bff34e3Sthurlow * 17194bff34e3Sthurlow * XXX: Todo - Ask the server to set the 17204bff34e3Sthurlow * set the delete-on-close flag. 17214bff34e3Sthurlow */ 17224bff34e3Sthurlow mutex_exit(&np->r_statelock); 17234bff34e3Sthurlow error = EBUSY; 17244bff34e3Sthurlow goto out; 17254bff34e3Sthurlow } else { 17264bff34e3Sthurlow mutex_exit(&np->r_statelock); 17274bff34e3Sthurlow 17284bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 17294bff34e3Sthurlow error = smbfs_smb_delete(np, &scred, NULL, 0, 0); 17304bff34e3Sthurlow smb_credrele(&scred); 17314bff34e3Sthurlow 17324bff34e3Sthurlow } 17334bff34e3Sthurlow 17344bff34e3Sthurlow VN_RELE(vp); 17354bff34e3Sthurlow 17364bff34e3Sthurlow out: 17374bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 17384bff34e3Sthurlow 17394bff34e3Sthurlow return (error); 17404bff34e3Sthurlow } 17414bff34e3Sthurlow 17424bff34e3Sthurlow 17434bff34e3Sthurlow /* 17444bff34e3Sthurlow * XXX 17454bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 17464bff34e3Sthurlow * lookups, per PSARC 2007/244. 17474bff34e3Sthurlow */ 17484bff34e3Sthurlow /* ARGSUSED */ 17494bff34e3Sthurlow static int 17504bff34e3Sthurlow smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 17514bff34e3Sthurlow caller_context_t *ct, int flags) 17524bff34e3Sthurlow { 17534bff34e3Sthurlow /* vnode_t *realvp; */ 17544bff34e3Sthurlow 17554bff34e3Sthurlow if (curproc->p_zone != VTOSMI(odvp)->smi_zone || 17564bff34e3Sthurlow curproc->p_zone != VTOSMI(ndvp)->smi_zone) 17574bff34e3Sthurlow return (EPERM); 17584bff34e3Sthurlow 17594bff34e3Sthurlow if (VTOSMI(odvp)->smi_flags & SMI_DEAD || 17604bff34e3Sthurlow VTOSMI(ndvp)->smi_flags & SMI_DEAD || 17614bff34e3Sthurlow odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED || 17624bff34e3Sthurlow ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 17634bff34e3Sthurlow return (EIO); 17644bff34e3Sthurlow 17654bff34e3Sthurlow return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct)); 17664bff34e3Sthurlow } 17674bff34e3Sthurlow 17684bff34e3Sthurlow /* 17694bff34e3Sthurlow * smbfsrename does the real work of renaming in SMBFS 17704bff34e3Sthurlow */ 17714bff34e3Sthurlow /* ARGSUSED */ 17724bff34e3Sthurlow static int 17734bff34e3Sthurlow smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 17744bff34e3Sthurlow caller_context_t *ct) 17754bff34e3Sthurlow { 17764bff34e3Sthurlow int error; 17774bff34e3Sthurlow int nvp_locked = 0; 17784bff34e3Sthurlow vnode_t *nvp = NULL; 17794bff34e3Sthurlow vnode_t *ovp = NULL; 17804bff34e3Sthurlow smbnode_t *onp; 17814bff34e3Sthurlow smbnode_t *odnp; 17824bff34e3Sthurlow smbnode_t *ndnp; 17834bff34e3Sthurlow struct smb_cred scred; 17844bff34e3Sthurlow /* enum smbfsstat status; */ 17854bff34e3Sthurlow 17864bff34e3Sthurlow ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone); 17874bff34e3Sthurlow 17884bff34e3Sthurlow if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 || 17894bff34e3Sthurlow strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0) 17904bff34e3Sthurlow return (EINVAL); 17914bff34e3Sthurlow 17924bff34e3Sthurlow /* 17934bff34e3Sthurlow * Check that everything is on the same filesystem. 17944bff34e3Sthurlow * vn_rename checks the fsid's, but in case we don't 17954bff34e3Sthurlow * fill those in correctly, check here too. 17964bff34e3Sthurlow */ 17974bff34e3Sthurlow if (odvp->v_vfsp != ndvp->v_vfsp) 17984bff34e3Sthurlow return (EXDEV); 17994bff34e3Sthurlow 18004bff34e3Sthurlow odnp = VTOSMB(odvp); 18014bff34e3Sthurlow ndnp = VTOSMB(ndvp); 18024bff34e3Sthurlow 18034bff34e3Sthurlow /* 18044bff34e3Sthurlow * Avoid deadlock here on old vs new directory nodes 18054bff34e3Sthurlow * by always taking the locks in order of address. 18064bff34e3Sthurlow * The order is arbitrary, but must be consistent. 18074bff34e3Sthurlow */ 18084bff34e3Sthurlow if (odnp < ndnp) { 18094bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 18104bff34e3Sthurlow SMBINTR(odvp))) 18114bff34e3Sthurlow return (EINTR); 18124bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 18134bff34e3Sthurlow SMBINTR(ndvp))) { 18144bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 18154bff34e3Sthurlow return (EINTR); 18164bff34e3Sthurlow } 18174bff34e3Sthurlow } else { 18184bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 18194bff34e3Sthurlow SMBINTR(ndvp))) 18204bff34e3Sthurlow return (EINTR); 18214bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 18224bff34e3Sthurlow SMBINTR(odvp))) { 18234bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 18244bff34e3Sthurlow return (EINTR); 18254bff34e3Sthurlow } 18264bff34e3Sthurlow } 18274bff34e3Sthurlow /* 18284bff34e3Sthurlow * No returns after this point (goto out) 18294bff34e3Sthurlow */ 18304bff34e3Sthurlow 18314bff34e3Sthurlow /* 18324bff34e3Sthurlow * Need write access on source and target. 18334bff34e3Sthurlow * Server takes care of most checks. 18344bff34e3Sthurlow */ 18354bff34e3Sthurlow error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct); 18364bff34e3Sthurlow if (error) 18374bff34e3Sthurlow goto out; 18384bff34e3Sthurlow if (odvp != ndvp) { 18394bff34e3Sthurlow error = smbfs_access(ndvp, VWRITE, 0, cr, ct); 18404bff34e3Sthurlow if (error) 18414bff34e3Sthurlow goto out; 18424bff34e3Sthurlow } 18434bff34e3Sthurlow 18444bff34e3Sthurlow /* 18454bff34e3Sthurlow * Lookup the source name. Must already exist. 18464bff34e3Sthurlow */ 18474bff34e3Sthurlow error = smbfslookup(odvp, onm, &ovp, cr, 0, ct); 18484bff34e3Sthurlow if (error) 18494bff34e3Sthurlow goto out; 18504bff34e3Sthurlow 18514bff34e3Sthurlow /* 18524bff34e3Sthurlow * Lookup the target file. If it exists, it needs to be 18534bff34e3Sthurlow * checked to see whether it is a mount point and whether 18544bff34e3Sthurlow * it is active (open). 18554bff34e3Sthurlow */ 18564bff34e3Sthurlow error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct); 18574bff34e3Sthurlow if (!error) { 18584bff34e3Sthurlow /* 18594bff34e3Sthurlow * Target (nvp) already exists. Check that it 18604bff34e3Sthurlow * has the same type as the source. The server 18614bff34e3Sthurlow * will check this also, (and more reliably) but 18624bff34e3Sthurlow * this lets us return the correct error codes. 18634bff34e3Sthurlow */ 18644bff34e3Sthurlow if (ovp->v_type == VDIR) { 18654bff34e3Sthurlow if (nvp->v_type != VDIR) { 18664bff34e3Sthurlow error = ENOTDIR; 18674bff34e3Sthurlow goto out; 18684bff34e3Sthurlow } 18694bff34e3Sthurlow } else { 18704bff34e3Sthurlow if (nvp->v_type == VDIR) { 18714bff34e3Sthurlow error = EISDIR; 18724bff34e3Sthurlow goto out; 18734bff34e3Sthurlow } 18744bff34e3Sthurlow } 18754bff34e3Sthurlow 18764bff34e3Sthurlow /* 18774bff34e3Sthurlow * POSIX dictates that when the source and target 18784bff34e3Sthurlow * entries refer to the same file object, rename 18794bff34e3Sthurlow * must do nothing and exit without error. 18804bff34e3Sthurlow */ 18814bff34e3Sthurlow if (ovp == nvp) { 18824bff34e3Sthurlow error = 0; 18834bff34e3Sthurlow goto out; 18844bff34e3Sthurlow } 18854bff34e3Sthurlow 18864bff34e3Sthurlow /* 18874bff34e3Sthurlow * Also must ensure the target is not a mount point, 18884bff34e3Sthurlow * and keep mount/umount away until we're done. 18894bff34e3Sthurlow */ 18904bff34e3Sthurlow if (vn_vfsrlock(nvp)) { 18914bff34e3Sthurlow error = EBUSY; 18924bff34e3Sthurlow goto out; 18934bff34e3Sthurlow } 18944bff34e3Sthurlow nvp_locked = 1; 18954bff34e3Sthurlow if (vn_mountedvfs(nvp) != NULL) { 18964bff34e3Sthurlow error = EBUSY; 18974bff34e3Sthurlow goto out; 18984bff34e3Sthurlow } 18994bff34e3Sthurlow 19004bff34e3Sthurlow #ifdef NOT_YET 19014bff34e3Sthurlow /* 19024bff34e3Sthurlow * Purge the name cache of all references to this vnode 19034bff34e3Sthurlow * so that we can check the reference count to infer 19044bff34e3Sthurlow * whether it is active or not. 19054bff34e3Sthurlow */ 19064bff34e3Sthurlow /* 19074bff34e3Sthurlow * First just remove the entry from the name cache, as it 19084bff34e3Sthurlow * is most likely the only entry for this vp. 19094bff34e3Sthurlow */ 19104bff34e3Sthurlow dnlc_remove(ndvp, nnm); 19114bff34e3Sthurlow /* 19124bff34e3Sthurlow * If the file has a v_count > 1 then there may be more 19134bff34e3Sthurlow * than one entry in the name cache due multiple links 19144bff34e3Sthurlow * or an open file, but we don't have the real reference 19154bff34e3Sthurlow * count so flush all possible entries. 19164bff34e3Sthurlow */ 19174bff34e3Sthurlow if (nvp->v_count > 1) 19184bff34e3Sthurlow dnlc_purge_vp(nvp); 19194bff34e3Sthurlow #endif 19204bff34e3Sthurlow 19214bff34e3Sthurlow if (nvp->v_count > 1 && nvp->v_type != VDIR) { 19224bff34e3Sthurlow /* 19234bff34e3Sthurlow * The target file exists, is not the same as 19244bff34e3Sthurlow * the source file, and is active. Other FS 19254bff34e3Sthurlow * implementations unlink the target here. 19264bff34e3Sthurlow * For SMB, we don't assume we can remove an 19274bff34e3Sthurlow * open file. Return an error instead. 19284bff34e3Sthurlow * Darwin returned an error here too. 19294bff34e3Sthurlow */ 19304bff34e3Sthurlow error = EEXIST; 19314bff34e3Sthurlow goto out; 19324bff34e3Sthurlow } 19334bff34e3Sthurlow } /* nvp */ 19344bff34e3Sthurlow 19354bff34e3Sthurlow #ifdef NOT_YET 19364bff34e3Sthurlow dnlc_remove(odvp, onm); 19374bff34e3Sthurlow dnlc_remove(ndvp, nnm); 19384bff34e3Sthurlow #endif 19394bff34e3Sthurlow 19404bff34e3Sthurlow onp = VTOSMB(ovp); 19414bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 19424bff34e3Sthurlow error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred); 19434bff34e3Sthurlow smb_credrele(&scred); 19444bff34e3Sthurlow 19454bff34e3Sthurlow 19464bff34e3Sthurlow out: 19474bff34e3Sthurlow if (nvp) { 19484bff34e3Sthurlow if (nvp_locked) 19494bff34e3Sthurlow vn_vfsunlock(nvp); 19504bff34e3Sthurlow VN_RELE(nvp); 19514bff34e3Sthurlow } 19524bff34e3Sthurlow if (ovp) 19534bff34e3Sthurlow VN_RELE(ovp); 19544bff34e3Sthurlow 19554bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 19564bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 19574bff34e3Sthurlow 19584bff34e3Sthurlow return (error); 19594bff34e3Sthurlow } 19604bff34e3Sthurlow 19614bff34e3Sthurlow /* 19624bff34e3Sthurlow * XXX 19634bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 19644bff34e3Sthurlow * it in order to create an ACL when an object is created. 19654bff34e3Sthurlow * 19664bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 19674bff34e3Sthurlow * lookups, per PSARC 2007/244. 19684bff34e3Sthurlow */ 19694bff34e3Sthurlow /* ARGSUSED */ 19704bff34e3Sthurlow static int 19714bff34e3Sthurlow smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, 19724bff34e3Sthurlow cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) 19734bff34e3Sthurlow { 19744bff34e3Sthurlow vnode_t *vp; 19754bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 19764bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 19774bff34e3Sthurlow struct smb_cred scred; 19784bff34e3Sthurlow struct smbfattr fattr; 19794bff34e3Sthurlow const char *name = (const char *) nm; 19804bff34e3Sthurlow int nmlen = strlen(name); 19814bff34e3Sthurlow int error, hiderr; 19824bff34e3Sthurlow 19834bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 19844bff34e3Sthurlow return (EPERM); 19854bff34e3Sthurlow 19864bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 19874bff34e3Sthurlow return (EIO); 19884bff34e3Sthurlow 19894bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 19904bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 19914bff34e3Sthurlow return (EEXIST); 19924bff34e3Sthurlow 19934bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 19944bff34e3Sthurlow return (EINTR); 19954bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 19964bff34e3Sthurlow 19974bff34e3Sthurlow /* 19984bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 19994bff34e3Sthurlow * No use of any shared fid or fctx... 20004bff34e3Sthurlow */ 20014bff34e3Sthurlow 20024bff34e3Sthurlow /* 20034bff34e3Sthurlow * Require write access in the containing directory. 20044bff34e3Sthurlow */ 20054bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 20064bff34e3Sthurlow if (error) 20074bff34e3Sthurlow goto out; 20084bff34e3Sthurlow 20094bff34e3Sthurlow error = smbfs_smb_mkdir(dnp, name, nmlen, &scred); 20104bff34e3Sthurlow if (error) 20114bff34e3Sthurlow goto out; 20124bff34e3Sthurlow 20134bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 20144bff34e3Sthurlow if (error) 20154bff34e3Sthurlow goto out; 20164bff34e3Sthurlow 20174bff34e3Sthurlow smbfs_attr_touchdir(dnp); 20184bff34e3Sthurlow 20194bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 20204bff34e3Sthurlow if (error) 20214bff34e3Sthurlow goto out; 20224bff34e3Sthurlow 20234bff34e3Sthurlow #ifdef NOT_YET 20244bff34e3Sthurlow dnlc_update(dvp, name, vp); 20254bff34e3Sthurlow #endif 20264bff34e3Sthurlow 20274bff34e3Sthurlow if (name[0] == '.') 20284bff34e3Sthurlow if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred))) 20294bff34e3Sthurlow SMBVDEBUG("hide failure %d\n", hiderr); 20304bff34e3Sthurlow 20314bff34e3Sthurlow /* Success! */ 20324bff34e3Sthurlow *vpp = vp; 20334bff34e3Sthurlow error = 0; 20344bff34e3Sthurlow out: 20354bff34e3Sthurlow smb_credrele(&scred); 20364bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 20374bff34e3Sthurlow 20384bff34e3Sthurlow if (name != nm) 20394bff34e3Sthurlow smbfs_name_free(name, nmlen); 20404bff34e3Sthurlow 20414bff34e3Sthurlow return (error); 20424bff34e3Sthurlow } 20434bff34e3Sthurlow 20444bff34e3Sthurlow /* 20454bff34e3Sthurlow * XXX 20464bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 20474bff34e3Sthurlow * lookups, per PSARC 2007/244. 20484bff34e3Sthurlow */ 20494bff34e3Sthurlow /* ARGSUSED */ 20504bff34e3Sthurlow static int 20514bff34e3Sthurlow smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, 20524bff34e3Sthurlow caller_context_t *ct, int flags) 20534bff34e3Sthurlow { 20544bff34e3Sthurlow vnode_t *vp = NULL; 20554bff34e3Sthurlow int vp_locked = 0; 20564bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 20574bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 20584bff34e3Sthurlow struct smbnode *np; 20594bff34e3Sthurlow struct smb_cred scred; 20604bff34e3Sthurlow int error; 20614bff34e3Sthurlow 20624bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 20634bff34e3Sthurlow return (EPERM); 20644bff34e3Sthurlow 20654bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 20664bff34e3Sthurlow return (EIO); 20674bff34e3Sthurlow 20684bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 20694bff34e3Sthurlow return (EINTR); 20704bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 20714bff34e3Sthurlow 20724bff34e3Sthurlow /* 20734bff34e3Sthurlow * Require w/x access in the containing directory. 20744bff34e3Sthurlow * Server handles all other access checks. 20754bff34e3Sthurlow */ 20764bff34e3Sthurlow error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct); 20774bff34e3Sthurlow if (error) 20784bff34e3Sthurlow goto out; 20794bff34e3Sthurlow 20804bff34e3Sthurlow /* 20814bff34e3Sthurlow * First lookup the entry to be removed. 20824bff34e3Sthurlow */ 20834bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 20844bff34e3Sthurlow if (error) 20854bff34e3Sthurlow goto out; 20864bff34e3Sthurlow np = VTOSMB(vp); 20874bff34e3Sthurlow 20884bff34e3Sthurlow /* 20894bff34e3Sthurlow * Disallow rmdir of "." or current dir, or the FS root. 20904bff34e3Sthurlow * Also make sure it's a directory, not a mount point, 20914bff34e3Sthurlow * and lock to keep mount/umount away until we're done. 20924bff34e3Sthurlow */ 20934bff34e3Sthurlow if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) { 20944bff34e3Sthurlow error = EINVAL; 20954bff34e3Sthurlow goto out; 20964bff34e3Sthurlow } 20974bff34e3Sthurlow if (vp->v_type != VDIR) { 20984bff34e3Sthurlow error = ENOTDIR; 20994bff34e3Sthurlow goto out; 21004bff34e3Sthurlow } 21014bff34e3Sthurlow if (vn_vfsrlock(vp)) { 21024bff34e3Sthurlow error = EBUSY; 21034bff34e3Sthurlow goto out; 21044bff34e3Sthurlow } 21054bff34e3Sthurlow vp_locked = 1; 21064bff34e3Sthurlow if (vn_mountedvfs(vp) != NULL) { 21074bff34e3Sthurlow error = EBUSY; 21084bff34e3Sthurlow goto out; 21094bff34e3Sthurlow } 21104bff34e3Sthurlow 21114bff34e3Sthurlow error = smbfs_smb_rmdir(np, &scred); 21124bff34e3Sthurlow if (error) 21134bff34e3Sthurlow goto out; 21144bff34e3Sthurlow 21154bff34e3Sthurlow mutex_enter(&np->r_statelock); 21164bff34e3Sthurlow dnp->n_flag |= NMODIFIED; 21174bff34e3Sthurlow mutex_exit(&np->r_statelock); 21184bff34e3Sthurlow smbfs_attr_touchdir(dnp); 21194bff34e3Sthurlow #ifdef NOT_YET 21204bff34e3Sthurlow dnlc_remove(dvp, nm); 21214bff34e3Sthurlow dnlc_purge_vp(vp); 21224bff34e3Sthurlow #endif 21234bff34e3Sthurlow smb_rmhash(np); 21244bff34e3Sthurlow 21254bff34e3Sthurlow out: 21264bff34e3Sthurlow if (vp) { 21274bff34e3Sthurlow if (vp_locked) 21284bff34e3Sthurlow vn_vfsunlock(vp); 21294bff34e3Sthurlow VN_RELE(vp); 21304bff34e3Sthurlow } 21314bff34e3Sthurlow smb_credrele(&scred); 21324bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 21334bff34e3Sthurlow 21344bff34e3Sthurlow return (error); 21354bff34e3Sthurlow } 21364bff34e3Sthurlow 21374bff34e3Sthurlow 21384bff34e3Sthurlow /* ARGSUSED */ 21394bff34e3Sthurlow static int 21404bff34e3Sthurlow smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp, 21414bff34e3Sthurlow caller_context_t *ct, int flags) 21424bff34e3Sthurlow { 21434bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 21444bff34e3Sthurlow int error = 0; 21454bff34e3Sthurlow smbmntinfo_t *smi; 21464bff34e3Sthurlow 21474bff34e3Sthurlow smi = VTOSMI(vp); 21484bff34e3Sthurlow 21494bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 21504bff34e3Sthurlow return (EIO); 21514bff34e3Sthurlow 21524bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 21534bff34e3Sthurlow return (EIO); 21544bff34e3Sthurlow 21554bff34e3Sthurlow /* 21564bff34e3Sthurlow * Require read access in the directory. 21574bff34e3Sthurlow */ 21584bff34e3Sthurlow error = smbfs_access(vp, VREAD, 0, cr, ct); 21594bff34e3Sthurlow if (error) 21604bff34e3Sthurlow return (error); 21614bff34e3Sthurlow 21624bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 21634bff34e3Sthurlow 21644bff34e3Sthurlow /* 21654bff34e3Sthurlow * XXX: Todo readdir cache here 21664bff34e3Sthurlow * Note: NFS code is just below this. 21674bff34e3Sthurlow * 21684bff34e3Sthurlow * I am serializing the entire readdir opreation 21694bff34e3Sthurlow * now since we have not yet implemented readdir 21704bff34e3Sthurlow * cache. This fix needs to be revisited once 21714bff34e3Sthurlow * we implement readdir cache. 21724bff34e3Sthurlow */ 21734bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 21744bff34e3Sthurlow return (EINTR); 21754bff34e3Sthurlow 21764bff34e3Sthurlow error = smbfs_readvdir(vp, uiop, cr, eofp, ct); 21774bff34e3Sthurlow 21784bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 21794bff34e3Sthurlow 21804bff34e3Sthurlow return (error); 21814bff34e3Sthurlow } 21824bff34e3Sthurlow 21834bff34e3Sthurlow /* ARGSUSED */ 21844bff34e3Sthurlow static int 21854bff34e3Sthurlow smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 21864bff34e3Sthurlow caller_context_t *ct) 21874bff34e3Sthurlow { 21884bff34e3Sthurlow size_t dbufsiz; 21894bff34e3Sthurlow struct dirent64 *dp; 21904bff34e3Sthurlow struct smb_cred scred; 21914bff34e3Sthurlow vnode_t *newvp; 21924bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 21934bff34e3Sthurlow int nmlen, reclen, error = 0; 21944bff34e3Sthurlow long offset, limit; 21954bff34e3Sthurlow struct smbfs_fctx *ctx; 21964bff34e3Sthurlow 21974bff34e3Sthurlow ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); 21984bff34e3Sthurlow 21994bff34e3Sthurlow /* Make sure we serialize for n_dirseq use. */ 22004bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER)); 22014bff34e3Sthurlow 22024bff34e3Sthurlow /* Min size is DIRENT64_RECLEN(256) rounded up. */ 22034bff34e3Sthurlow if (uio->uio_resid < 512 || uio->uio_offset < 0) 22044bff34e3Sthurlow return (EINVAL); 22054bff34e3Sthurlow 22064bff34e3Sthurlow /* 22074bff34e3Sthurlow * This dnlc_purge_vp ensures that name cache for this dir will be 22084bff34e3Sthurlow * current - it'll only have the items for which the smbfs_nget 22094bff34e3Sthurlow * MAKEENTRY happened. 22104bff34e3Sthurlow */ 22114bff34e3Sthurlow #ifdef NOT_YET 22124bff34e3Sthurlow if (smbfs_fastlookup) 22134bff34e3Sthurlow dnlc_purge_vp(vp); 22144bff34e3Sthurlow #endif 22154bff34e3Sthurlow SMBVDEBUG("dirname='%s'\n", np->n_rpath); 22164bff34e3Sthurlow smb_credinit(&scred, curproc, cr); 22174bff34e3Sthurlow dbufsiz = DIRENT64_RECLEN(MAXNAMELEN); 22184bff34e3Sthurlow dp = kmem_alloc(dbufsiz, KM_SLEEP); 22194bff34e3Sthurlow 22204bff34e3Sthurlow offset = uio->uio_offset; /* NB: "cookie" */ 22214bff34e3Sthurlow limit = uio->uio_resid / DIRENT64_RECLEN(1); 22224bff34e3Sthurlow SMBVDEBUG("offset=0x%ld, limit=0x%ld\n", offset, limit); 22234bff34e3Sthurlow 22244bff34e3Sthurlow if (offset == 0) { 22254bff34e3Sthurlow /* Don't know EOF until findclose */ 22264bff34e3Sthurlow np->n_direof = -1; 22274bff34e3Sthurlow } else if (offset == np->n_direof) { 22284bff34e3Sthurlow /* Arrived at end of directory. */ 22294bff34e3Sthurlow goto out; 22304bff34e3Sthurlow } 22314bff34e3Sthurlow 22324bff34e3Sthurlow /* 22334bff34e3Sthurlow * Generate the "." and ".." entries here so we can 22344bff34e3Sthurlow * (1) make sure they appear (but only once), and 22354bff34e3Sthurlow * (2) deal with getting their I numbers which the 22364bff34e3Sthurlow * findnext below does only for normal names. 22374bff34e3Sthurlow */ 22384bff34e3Sthurlow while (limit && offset < 2) { 22394bff34e3Sthurlow limit--; 22404bff34e3Sthurlow reclen = DIRENT64_RECLEN(offset + 1); 22414bff34e3Sthurlow bzero(dp, reclen); 22424bff34e3Sthurlow /*LINTED*/ 22434bff34e3Sthurlow dp->d_reclen = reclen; 22444bff34e3Sthurlow /* Tricky: offset 0 is ".", offset 1 is ".." */ 22454bff34e3Sthurlow dp->d_name[0] = '.'; 22464bff34e3Sthurlow dp->d_name[1] = '.'; 22474bff34e3Sthurlow dp->d_name[offset + 1] = '\0'; 22484bff34e3Sthurlow /* 22494bff34e3Sthurlow * Want the real I-numbers for the "." and ".." 22504bff34e3Sthurlow * entries. For these two names, we know that 22514bff34e3Sthurlow * smbfslookup can do this all locally. 22524bff34e3Sthurlow */ 22534bff34e3Sthurlow error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct); 22544bff34e3Sthurlow if (error) { 22554bff34e3Sthurlow dp->d_ino = np->n_ino + offset; /* fiction */ 22564bff34e3Sthurlow } else { 22574bff34e3Sthurlow dp->d_ino = VTOSMB(newvp)->n_ino; 22584bff34e3Sthurlow VN_RELE(newvp); 22594bff34e3Sthurlow } 22604bff34e3Sthurlow dp->d_off = offset + 1; /* see d_off below */ 22614bff34e3Sthurlow error = uiomove(dp, dp->d_reclen, UIO_READ, uio); 22624bff34e3Sthurlow if (error) 22634bff34e3Sthurlow goto out; 22644bff34e3Sthurlow uio->uio_offset = ++offset; 22654bff34e3Sthurlow } 22664bff34e3Sthurlow if (limit == 0) 22674bff34e3Sthurlow goto out; 22684bff34e3Sthurlow if (offset != np->n_dirofs || np->n_dirseq == NULL) { 22694bff34e3Sthurlow SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs); 22704bff34e3Sthurlow if (np->n_dirseq) { 22714bff34e3Sthurlow (void) smbfs_smb_findclose(np->n_dirseq, &scred); 22724bff34e3Sthurlow np->n_dirseq = NULL; 22734bff34e3Sthurlow } 22744bff34e3Sthurlow np->n_dirofs = 2; 22754bff34e3Sthurlow error = smbfs_smb_findopen(np, "*", 1, 22764bff34e3Sthurlow SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 22774bff34e3Sthurlow &scred, &ctx); 22784bff34e3Sthurlow if (error) { 22794bff34e3Sthurlow SMBVDEBUG("can not open search, error = %d", error); 22804bff34e3Sthurlow goto out; 22814bff34e3Sthurlow } 22824bff34e3Sthurlow np->n_dirseq = ctx; 22834bff34e3Sthurlow } else 22844bff34e3Sthurlow ctx = np->n_dirseq; 22854bff34e3Sthurlow while (np->n_dirofs < offset) { 22864bff34e3Sthurlow if (smbfs_smb_findnext(ctx, offset - np->n_dirofs++, 22874bff34e3Sthurlow &scred) != 0) { 22884bff34e3Sthurlow (void) smbfs_smb_findclose(np->n_dirseq, &scred); 22894bff34e3Sthurlow np->n_dirseq = NULL; 22904bff34e3Sthurlow np->n_direof = np->n_dirofs; 22914bff34e3Sthurlow np->n_dirofs = 0; 22924bff34e3Sthurlow *eofp = 1; 22934bff34e3Sthurlow error = 0; 22944bff34e3Sthurlow goto out; 22954bff34e3Sthurlow } 22964bff34e3Sthurlow } 22974bff34e3Sthurlow error = 0; 22984bff34e3Sthurlow for (; limit; limit--) { 22994bff34e3Sthurlow error = smbfs_smb_findnext(ctx, limit, &scred); 23004bff34e3Sthurlow if (error) { 23014bff34e3Sthurlow if (error == EBADRPC) 23024bff34e3Sthurlow error = ENOENT; 23034bff34e3Sthurlow (void) smbfs_smb_findclose(np->n_dirseq, &scred); 23044bff34e3Sthurlow np->n_dirseq = NULL; 23054bff34e3Sthurlow np->n_direof = np->n_dirofs; 23064bff34e3Sthurlow np->n_dirofs = 0; 23074bff34e3Sthurlow *eofp = 1; 23084bff34e3Sthurlow error = 0; 23094bff34e3Sthurlow break; 23104bff34e3Sthurlow } 23114bff34e3Sthurlow np->n_dirofs++; 23124bff34e3Sthurlow /* Sanity check the name length. */ 23134bff34e3Sthurlow nmlen = ctx->f_nmlen; 23144bff34e3Sthurlow if (nmlen > (MAXNAMELEN - 1)) { 23154bff34e3Sthurlow nmlen = MAXNAMELEN - 1; 23164bff34e3Sthurlow SMBVDEBUG("Truncating name: %s\n", ctx->f_name); 23174bff34e3Sthurlow } 23184bff34e3Sthurlow reclen = DIRENT64_RECLEN(nmlen); 23194bff34e3Sthurlow if (uio->uio_resid < reclen) 23204bff34e3Sthurlow break; 23214bff34e3Sthurlow bzero(dp, reclen); 23224bff34e3Sthurlow /*LINTED*/ 23234bff34e3Sthurlow dp->d_reclen = reclen; 23244bff34e3Sthurlow dp->d_ino = ctx->f_attr.fa_ino; 23254bff34e3Sthurlow /* 23264bff34e3Sthurlow * Note: d_off is the offset that a user-level program 23274bff34e3Sthurlow * should seek to for reading the _next_ directory entry. 23284bff34e3Sthurlow * See libc: readdir, telldir, seekdir 23294bff34e3Sthurlow */ 23304bff34e3Sthurlow dp->d_off = offset + 1; 23314bff34e3Sthurlow bcopy(ctx->f_name, dp->d_name, nmlen); 23324bff34e3Sthurlow dp->d_name[nmlen] = '\0'; 23334bff34e3Sthurlow #ifdef NOT_YET 23344bff34e3Sthurlow if (smbfs_fastlookup) { 23354bff34e3Sthurlow if (smbfs_nget(vp, ctx->f_name, 23364bff34e3Sthurlow ctx->f_nmlen, &ctx->f_attr, &newvp) == 0) 23374bff34e3Sthurlow VN_RELE(newvp); 23384bff34e3Sthurlow } 23394bff34e3Sthurlow #endif /* NOT_YET */ 23404bff34e3Sthurlow error = uiomove(dp, dp->d_reclen, UIO_READ, uio); 23414bff34e3Sthurlow if (error) 23424bff34e3Sthurlow break; 23434bff34e3Sthurlow uio->uio_offset = ++offset; 23444bff34e3Sthurlow } 23454bff34e3Sthurlow if (error == ENOENT) 23464bff34e3Sthurlow error = 0; 23474bff34e3Sthurlow out: 23484bff34e3Sthurlow kmem_free(dp, dbufsiz); 23494bff34e3Sthurlow smb_credrele(&scred); 23504bff34e3Sthurlow return (error); 23514bff34e3Sthurlow } 23524bff34e3Sthurlow 23534bff34e3Sthurlow 23544bff34e3Sthurlow /* 23554bff34e3Sthurlow * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK 23564bff34e3Sthurlow * are optional functions that are called by: 23574bff34e3Sthurlow * getdents, before/after VOP_READDIR 23584bff34e3Sthurlow * pread, before/after ... VOP_READ 23594bff34e3Sthurlow * pwrite, before/after ... VOP_WRITE 23604bff34e3Sthurlow * (other places) 23614bff34e3Sthurlow * 23624bff34e3Sthurlow * Careful here: None of the above check for any 23634bff34e3Sthurlow * error returns from VOP_RWLOCK / VOP_RWUNLOCK! 23644bff34e3Sthurlow * In fact, the return value from _rwlock is NOT 23654bff34e3Sthurlow * an error code, but V_WRITELOCK_TRUE / _FALSE. 23664bff34e3Sthurlow * 23674bff34e3Sthurlow * Therefore, it's up to _this_ code to make sure 23684bff34e3Sthurlow * the lock state remains balanced, which means 23694bff34e3Sthurlow * we can't "bail out" on interrupts, etc. 23704bff34e3Sthurlow */ 23714bff34e3Sthurlow 23724bff34e3Sthurlow /* ARGSUSED2 */ 23734bff34e3Sthurlow static int 23744bff34e3Sthurlow smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 23754bff34e3Sthurlow { 23764bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 23774bff34e3Sthurlow 23784bff34e3Sthurlow if (!write_lock) { 23794bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE); 23804bff34e3Sthurlow return (V_WRITELOCK_FALSE); 23814bff34e3Sthurlow } 23824bff34e3Sthurlow 23834bff34e3Sthurlow 23844bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE); 23854bff34e3Sthurlow return (V_WRITELOCK_TRUE); 23864bff34e3Sthurlow } 23874bff34e3Sthurlow 23884bff34e3Sthurlow /* ARGSUSED */ 23894bff34e3Sthurlow static void 23904bff34e3Sthurlow smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 23914bff34e3Sthurlow { 23924bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 23934bff34e3Sthurlow 23944bff34e3Sthurlow smbfs_rw_exit(&np->r_rwlock); 23954bff34e3Sthurlow } 23964bff34e3Sthurlow 23974bff34e3Sthurlow 23984bff34e3Sthurlow /* ARGSUSED */ 23994bff34e3Sthurlow static int 24004bff34e3Sthurlow smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 24014bff34e3Sthurlow { 24024bff34e3Sthurlow smbmntinfo_t *smi; 24034bff34e3Sthurlow 24044bff34e3Sthurlow smi = VTOSMI(vp); 24054bff34e3Sthurlow 24064bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 24074bff34e3Sthurlow return (EPERM); 24084bff34e3Sthurlow 24094bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 24104bff34e3Sthurlow return (EIO); 24114bff34e3Sthurlow 24124bff34e3Sthurlow /* 24134bff34e3Sthurlow * Because we stuff the readdir cookie into the offset field 24144bff34e3Sthurlow * someone may attempt to do an lseek with the cookie which 24154bff34e3Sthurlow * we want to succeed. 24164bff34e3Sthurlow */ 24174bff34e3Sthurlow if (vp->v_type == VDIR) 24184bff34e3Sthurlow return (0); 24194bff34e3Sthurlow 24204bff34e3Sthurlow /* Like NFS3, just check for 63-bit overflow. */ 24214bff34e3Sthurlow if (*noffp < 0) 24224bff34e3Sthurlow return (EINVAL); 24234bff34e3Sthurlow 24244bff34e3Sthurlow return (0); 24254bff34e3Sthurlow } 24264bff34e3Sthurlow 24274bff34e3Sthurlow 24284bff34e3Sthurlow /* 24294bff34e3Sthurlow * XXX 24304bff34e3Sthurlow * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service. 24314bff34e3Sthurlow */ 24324bff34e3Sthurlow static int 24334bff34e3Sthurlow smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 24344bff34e3Sthurlow offset_t offset, struct flk_callback *flk_cbp, cred_t *cr, 24354bff34e3Sthurlow caller_context_t *ct) 24364bff34e3Sthurlow { 24374bff34e3Sthurlow if (curproc->p_zone != VTOSMI(vp)->smi_zone) 24384bff34e3Sthurlow return (EIO); 24394bff34e3Sthurlow 24404bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 24414bff34e3Sthurlow return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct)); 24424bff34e3Sthurlow else 24434bff34e3Sthurlow return (ENOSYS); 24444bff34e3Sthurlow } 24454bff34e3Sthurlow 24464bff34e3Sthurlow /* 24474bff34e3Sthurlow * Free storage space associated with the specified vnode. The portion 24484bff34e3Sthurlow * to be freed is specified by bfp->l_start and bfp->l_len (already 24494bff34e3Sthurlow * normalized to a "whence" of 0). 24504bff34e3Sthurlow * 24514bff34e3Sthurlow * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc. 24524bff34e3Sthurlow */ 24534bff34e3Sthurlow /* ARGSUSED */ 24544bff34e3Sthurlow static int 24554bff34e3Sthurlow smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 24564bff34e3Sthurlow offset_t offset, cred_t *cr, caller_context_t *ct) 24574bff34e3Sthurlow { 24584bff34e3Sthurlow int error; 24594bff34e3Sthurlow smbmntinfo_t *smi; 24604bff34e3Sthurlow 24614bff34e3Sthurlow smi = VTOSMI(vp); 24624bff34e3Sthurlow 24634bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 24644bff34e3Sthurlow return (EIO); 24654bff34e3Sthurlow 24664bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 24674bff34e3Sthurlow return (EIO); 24684bff34e3Sthurlow 24694bff34e3Sthurlow ASSERT(vp->v_type == VREG); 24704bff34e3Sthurlow if (cmd != F_FREESP) 24714bff34e3Sthurlow return (EINVAL); 24724bff34e3Sthurlow 24734bff34e3Sthurlow /* 24744bff34e3Sthurlow * Like NFS3, no 32-bit offset checks here. 24754bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 24764bff34e3Sthurlow * when it has to fallback to a 32-bit call. 24774bff34e3Sthurlow */ 24784bff34e3Sthurlow 24794bff34e3Sthurlow error = convoff(vp, bfp, 0, offset); 24804bff34e3Sthurlow if (!error) { 24814bff34e3Sthurlow ASSERT(bfp->l_start >= 0); 24824bff34e3Sthurlow if (bfp->l_len == 0) { 24834bff34e3Sthurlow struct vattr va; 24844bff34e3Sthurlow 24854bff34e3Sthurlow /* 24864bff34e3Sthurlow * ftruncate should not change the ctime and 24874bff34e3Sthurlow * mtime if we truncate the file to its 24884bff34e3Sthurlow * previous size. 24894bff34e3Sthurlow */ 24904bff34e3Sthurlow va.va_mask = AT_SIZE; 24914bff34e3Sthurlow error = smbfsgetattr(vp, &va, cr); 24924bff34e3Sthurlow if (error || va.va_size == bfp->l_start) 24934bff34e3Sthurlow return (error); 24944bff34e3Sthurlow va.va_mask = AT_SIZE; 24954bff34e3Sthurlow va.va_size = bfp->l_start; 24964bff34e3Sthurlow error = smbfssetattr(vp, &va, 0, cr); 24974bff34e3Sthurlow } else 24984bff34e3Sthurlow error = EINVAL; 24994bff34e3Sthurlow } 25004bff34e3Sthurlow 25014bff34e3Sthurlow return (error); 25024bff34e3Sthurlow } 25034bff34e3Sthurlow 25044bff34e3Sthurlow /* ARGSUSED */ 25054bff34e3Sthurlow static int 25064bff34e3Sthurlow smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 25074bff34e3Sthurlow caller_context_t *ct) 25084bff34e3Sthurlow { 25094bff34e3Sthurlow smbmntinfo_t *smi; 25104bff34e3Sthurlow struct smb_share *ssp; 25114bff34e3Sthurlow 25124bff34e3Sthurlow smi = VTOSMI(vp); 25134bff34e3Sthurlow 25144bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 25154bff34e3Sthurlow return (EIO); 25164bff34e3Sthurlow 25174bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 25184bff34e3Sthurlow return (EIO); 25194bff34e3Sthurlow 25204bff34e3Sthurlow switch (cmd) { 25214bff34e3Sthurlow case _PC_FILESIZEBITS: 25224bff34e3Sthurlow ssp = smi->smi_share; 25234bff34e3Sthurlow if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) 25244bff34e3Sthurlow *valp = 64; 25254bff34e3Sthurlow else 25264bff34e3Sthurlow *valp = 32; 25274bff34e3Sthurlow break; 25284bff34e3Sthurlow 25294bff34e3Sthurlow case _PC_LINK_MAX: 25304bff34e3Sthurlow /* We only ever report one link to an object */ 25314bff34e3Sthurlow *valp = 1; 25324bff34e3Sthurlow break; 25334bff34e3Sthurlow 2534*7568150aSgwr case _PC_ACL_ENABLED: 2535*7568150aSgwr /* 2536*7568150aSgwr * Always say "yes" here. Our _getsecattr 2537*7568150aSgwr * will build a trivial ACL when needed, 2538*7568150aSgwr * i.e. when server does not have ACLs. 2539*7568150aSgwr */ 2540*7568150aSgwr *valp = _ACL_ACE_ENABLED; 2541*7568150aSgwr break; 2542*7568150aSgwr 25434bff34e3Sthurlow case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */ 25444bff34e3Sthurlow case _PC_XATTR_EXISTS: /* No xattrs yet */ 25454bff34e3Sthurlow *valp = 0; 25464bff34e3Sthurlow break; 25474bff34e3Sthurlow 25484bff34e3Sthurlow default: 25494bff34e3Sthurlow return (fs_pathconf(vp, cmd, valp, cr, ct)); 25504bff34e3Sthurlow } 25514bff34e3Sthurlow return (0); 25524bff34e3Sthurlow } 25534bff34e3Sthurlow 2554*7568150aSgwr /* ARGSUSED */ 2555*7568150aSgwr static int 2556*7568150aSgwr smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 2557*7568150aSgwr caller_context_t *ct) 2558*7568150aSgwr { 2559*7568150aSgwr vfs_t *vfsp; 2560*7568150aSgwr smbmntinfo_t *smi; 2561*7568150aSgwr int error, uid, gid; 2562*7568150aSgwr uint_t mask; 2563*7568150aSgwr 2564*7568150aSgwr vfsp = vp->v_vfsp; 2565*7568150aSgwr smi = VFTOSMI(vfsp); 2566*7568150aSgwr 2567*7568150aSgwr if (curproc->p_zone != smi->smi_zone) 2568*7568150aSgwr return (EIO); 2569*7568150aSgwr 2570*7568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 2571*7568150aSgwr return (EIO); 2572*7568150aSgwr 2573*7568150aSgwr /* 2574*7568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 2575*7568150aSgwr * so we should only see VSA_ACE, etc here. 2576*7568150aSgwr * Note: vn_create asks for VSA_DFACLCNT, 2577*7568150aSgwr * and it expects ENOSYS and empty data. 2578*7568150aSgwr */ 2579*7568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT | 2580*7568150aSgwr VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 2581*7568150aSgwr if (mask == 0) 2582*7568150aSgwr return (ENOSYS); 2583*7568150aSgwr 2584*7568150aSgwr /* XXX - access check ACE_READ_ACL? */ 2585*7568150aSgwr 2586*7568150aSgwr if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) { 2587*7568150aSgwr error = smbfs_getacl(vp, vsa, &uid, &gid, flag, cr); 2588*7568150aSgwr /* XXX: Save uid/gid somewhere? */ 2589*7568150aSgwr } else 2590*7568150aSgwr error = ENOSYS; 2591*7568150aSgwr 2592*7568150aSgwr if (error == ENOSYS) 2593*7568150aSgwr error = fs_fab_acl(vp, vsa, flag, cr, ct); 2594*7568150aSgwr 2595*7568150aSgwr return (error); 2596*7568150aSgwr } 2597*7568150aSgwr 2598*7568150aSgwr /* ARGSUSED */ 2599*7568150aSgwr static int 2600*7568150aSgwr smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 2601*7568150aSgwr caller_context_t *ct) 2602*7568150aSgwr { 2603*7568150aSgwr vfs_t *vfsp; 2604*7568150aSgwr smbmntinfo_t *smi; 2605*7568150aSgwr int error; 2606*7568150aSgwr uint_t mask; 2607*7568150aSgwr 2608*7568150aSgwr vfsp = vp->v_vfsp; 2609*7568150aSgwr smi = VFTOSMI(vfsp); 2610*7568150aSgwr 2611*7568150aSgwr if (curproc->p_zone != smi->smi_zone) 2612*7568150aSgwr return (EIO); 2613*7568150aSgwr 2614*7568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 2615*7568150aSgwr return (EIO); 2616*7568150aSgwr 2617*7568150aSgwr /* 2618*7568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 2619*7568150aSgwr * so we should only see VSA_ACE, etc here. 2620*7568150aSgwr */ 2621*7568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT); 2622*7568150aSgwr if (mask == 0) 2623*7568150aSgwr return (ENOSYS); 2624*7568150aSgwr 2625*7568150aSgwr /* 2626*7568150aSgwr * If and when smbfs_access is extended, we can 2627*7568150aSgwr * check ACE_WRITE_ACL here instead. (XXX todo) 2628*7568150aSgwr * For now, in-line parts of smbfs_access, 2629*7568150aSgwr * i.e. only allow _setacl by the owner, 2630*7568150aSgwr * and check for read-only FS. 2631*7568150aSgwr */ 2632*7568150aSgwr if (vfsp->vfs_flag & VFS_RDONLY) 2633*7568150aSgwr return (EROFS); 2634*7568150aSgwr if (crgetuid(cr) != smi->smi_args.uid) 2635*7568150aSgwr return (EACCES); 2636*7568150aSgwr 2637*7568150aSgwr if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) { 2638*7568150aSgwr error = smbfs_setacl(vp, vsa, -1, -1, flag, cr); 2639*7568150aSgwr } else 2640*7568150aSgwr error = ENOSYS; 2641*7568150aSgwr 2642*7568150aSgwr return (error); 2643*7568150aSgwr } 26444bff34e3Sthurlow 26454bff34e3Sthurlow 26464bff34e3Sthurlow /* 26474bff34e3Sthurlow * XXX 26484bff34e3Sthurlow * This op should eventually support PSARC 2007/268. 26494bff34e3Sthurlow */ 26504bff34e3Sthurlow static int 26514bff34e3Sthurlow smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr, 26524bff34e3Sthurlow caller_context_t *ct) 26534bff34e3Sthurlow { 26544bff34e3Sthurlow if (curproc->p_zone != VTOSMI(vp)->smi_zone) 26554bff34e3Sthurlow return (EIO); 26564bff34e3Sthurlow 26574bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 26584bff34e3Sthurlow return (fs_shrlock(vp, cmd, shr, flag, cr, ct)); 26594bff34e3Sthurlow else 26604bff34e3Sthurlow return (ENOSYS); 26614bff34e3Sthurlow } 2662