1 /*
   2  * Copyright (c) 2000-2001 Boris Popov
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. All advertising materials mentioning features or use of this software
  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  *
  32  * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  37  */
  38 
  39 #include <sys/systm.h>
  40 #include <sys/cred.h>
  41 #include <sys/vnode.h>
  42 #include <sys/vfs.h>
  43 #include <sys/filio.h>
  44 #include <sys/uio.h>
  45 #include <sys/dirent.h>
  46 #include <sys/errno.h>
  47 #include <sys/sunddi.h>
  48 #include <sys/sysmacros.h>
  49 #include <sys/kmem.h>
  50 #include <sys/cmn_err.h>
  51 #include <sys/vfs_opreg.h>
  52 #include <sys/policy.h>
  53 
  54 #include <netsmb/smb_osdep.h>
  55 #include <netsmb/smb.h>
  56 #include <netsmb/smb_conn.h>
  57 #include <netsmb/smb_subr.h>
  58 
  59 #include <smbfs/smbfs.h>
  60 #include <smbfs/smbfs_node.h>
  61 #include <smbfs/smbfs_subr.h>
  62 
  63 #include <sys/fs/smbfs_ioctl.h>
  64 #include <fs/fs_subr.h>
  65 
  66 /*
  67  * We assign directory offsets like the NFS client, where the
  68  * offset increments by _one_ after each directory entry.
  69  * Further, the entries "." and ".." are always at offsets
  70  * zero and one (respectively) and the "real" entries from
  71  * the server appear at offsets starting with two.  This
  72  * macro is used to initialize the n_dirofs field after
  73  * setting n_dirseq with a _findopen call.
  74  */
  75 #define FIRST_DIROFS    2
  76 
  77 /*
  78  * These characters are illegal in NTFS file names.
  79  * ref: http://support.microsoft.com/kb/147438
  80  *
  81  * Careful!  The check in the XATTR case skips the
  82  * first character to allow colon in XATTR names.
  83  */
  84 static const char illegal_chars[] = {
  85         ':',    /* colon - keep this first! */
  86         '\\',   /* back slash */
  87         '/',    /* slash */
  88         '*',    /* asterisk */
  89         '?',    /* question mark */
  90         '"',    /* double quote */
  91         '<', /* less than sign */
  92         '>', /* greater than sign */
  93         '|',    /* vertical bar */
  94         0
  95 };
  96 
  97 /*
  98  * Turning this on causes nodes to be created in the cache
  99  * during directory listings, normally avoiding a second
 100  * OtW attribute fetch just after a readdir.
 101  */
 102 int smbfs_fastlookup = 1;
 103 
 104 /* local static function defines */
 105 
 106 static int      smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
 107                         cred_t *);
 108 static int      smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
 109                         int cache_ok, caller_context_t *);
 110 static int      smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
 111                         cred_t *cr, caller_context_t *);
 112 static int      smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
 113 static int      smbfs_accessx(void *, int, cred_t *);
 114 static int      smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
 115                         caller_context_t *);
 116 static void     smbfs_rele_fid(smbnode_t *, struct smb_cred *);
 117 
 118 /*
 119  * These are the vnode ops routines which implement the vnode interface to
 120  * the networked file system.  These routines just take their parameters,
 121  * make them look networkish by putting the right info into interface structs,
 122  * and then calling the appropriate remote routine(s) to do the work.
 123  *
 124  * Note on directory name lookup cacheing:  If we detect a stale fhandle,
 125  * we purge the directory cache relative to that vnode.  This way, the
 126  * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
 127  * more details on smbnode locking.
 128  */
 129 
 130 static int      smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
 131 static int      smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
 132                         caller_context_t *);
 133 static int      smbfs_read(vnode_t *, struct uio *, int, cred_t *,
 134                         caller_context_t *);
 135 static int      smbfs_write(vnode_t *, struct uio *, int, cred_t *,
 136                         caller_context_t *);
 137 static int      smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
 138                         caller_context_t *);
 139 static int      smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
 140                         caller_context_t *);
 141 static int      smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
 142                         caller_context_t *);
 143 static int      smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
 144 static int      smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
 145 static void     smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
 146 static int      smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
 147                         int, vnode_t *, cred_t *, caller_context_t *,
 148                         int *, pathname_t *);
 149 static int      smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
 150                         int, vnode_t **, cred_t *, int, caller_context_t *,
 151                         vsecattr_t *);
 152 static int      smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
 153                         int);
 154 static int      smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
 155                         caller_context_t *, int);
 156 static int      smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
 157                         cred_t *, caller_context_t *, int, vsecattr_t *);
 158 static int      smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
 159                         caller_context_t *, int);
 160 static int      smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
 161                         caller_context_t *, int);
 162 static int      smbfs_rwlock(vnode_t *, int, caller_context_t *);
 163 static void     smbfs_rwunlock(vnode_t *, int, caller_context_t *);
 164 static int      smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
 165 static int      smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
 166                         struct flk_callback *, cred_t *, caller_context_t *);
 167 static int      smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
 168                         cred_t *, caller_context_t *);
 169 static int      smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 170                         caller_context_t *);
 171 static int      smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 172                         caller_context_t *);
 173 static int      smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
 174                         caller_context_t *);
 175 static int      smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 176                         caller_context_t *);
 177 
 178 /* Dummy function to use until correct function is ported in */
 179 int noop_vnodeop() {
 180         return (0);
 181 }
 182 
 183 struct vnodeops *smbfs_vnodeops = NULL;
 184 
 185 /*
 186  * Most unimplemented ops will return ENOSYS because of fs_nosys().
 187  * The only ops where that won't work are ACCESS (due to open(2)
 188  * failures) and ... (anything else left?)
 189  */
 190 const fs_operation_def_t smbfs_vnodeops_template[] = {
 191         { VOPNAME_OPEN,         { .vop_open = smbfs_open } },
 192         { VOPNAME_CLOSE,        { .vop_close = smbfs_close } },
 193         { VOPNAME_READ,         { .vop_read = smbfs_read } },
 194         { VOPNAME_WRITE,        { .vop_write = smbfs_write } },
 195         { VOPNAME_IOCTL,        { .vop_ioctl = smbfs_ioctl } },
 196         { VOPNAME_GETATTR,      { .vop_getattr = smbfs_getattr } },
 197         { VOPNAME_SETATTR,      { .vop_setattr = smbfs_setattr } },
 198         { VOPNAME_ACCESS,       { .vop_access = smbfs_access } },
 199         { VOPNAME_LOOKUP,       { .vop_lookup = smbfs_lookup } },
 200         { VOPNAME_CREATE,       { .vop_create = smbfs_create } },
 201         { VOPNAME_REMOVE,       { .vop_remove = smbfs_remove } },
 202         { VOPNAME_LINK,         { .error = fs_nosys } }, /* smbfs_link, */
 203         { VOPNAME_RENAME,       { .vop_rename = smbfs_rename } },
 204         { VOPNAME_MKDIR,        { .vop_mkdir = smbfs_mkdir } },
 205         { VOPNAME_RMDIR,        { .vop_rmdir = smbfs_rmdir } },
 206         { VOPNAME_READDIR,      { .vop_readdir = smbfs_readdir } },
 207         { VOPNAME_SYMLINK,      { .error = fs_nosys } }, /* smbfs_symlink, */
 208         { VOPNAME_READLINK,     { .error = fs_nosys } }, /* smbfs_readlink, */
 209         { VOPNAME_FSYNC,        { .vop_fsync = smbfs_fsync } },
 210         { VOPNAME_INACTIVE,     { .vop_inactive = smbfs_inactive } },
 211         { VOPNAME_FID,          { .error = fs_nosys } }, /* smbfs_fid, */
 212         { VOPNAME_RWLOCK,       { .vop_rwlock = smbfs_rwlock } },
 213         { VOPNAME_RWUNLOCK,     { .vop_rwunlock = smbfs_rwunlock } },
 214         { VOPNAME_SEEK,         { .vop_seek = smbfs_seek } },
 215         { VOPNAME_FRLOCK,       { .vop_frlock = smbfs_frlock } },
 216         { VOPNAME_SPACE,        { .vop_space = smbfs_space } },
 217         { VOPNAME_REALVP,       { .error = fs_nosys } }, /* smbfs_realvp, */
 218         { VOPNAME_GETPAGE,      { .error = fs_nosys } }, /* smbfs_getpage, */
 219         { VOPNAME_PUTPAGE,      { .error = fs_nosys } }, /* smbfs_putpage, */
 220         { VOPNAME_MAP,          { .error = fs_nosys } }, /* smbfs_map, */
 221         { VOPNAME_ADDMAP,       { .error = fs_nosys } }, /* smbfs_addmap, */
 222         { VOPNAME_DELMAP,       { .error = fs_nosys } }, /* smbfs_delmap, */
 223         { VOPNAME_DUMP,         { .error = fs_nosys } }, /* smbfs_dump, */
 224         { VOPNAME_PATHCONF,     { .vop_pathconf = smbfs_pathconf } },
 225         { VOPNAME_PAGEIO,       { .error = fs_nosys } }, /* smbfs_pageio, */
 226         { VOPNAME_SETSECATTR,   { .vop_setsecattr = smbfs_setsecattr } },
 227         { VOPNAME_GETSECATTR,   { .vop_getsecattr = smbfs_getsecattr } },
 228         { VOPNAME_SHRLOCK,      { .vop_shrlock = smbfs_shrlock } },
 229         { NULL,                 { NULL } }
 230 };
 231 
 232 /*
 233  * XXX
 234  * When new and relevant functionality is enabled, we should be
 235  * calling vfs_set_feature() to inform callers that pieces of
 236  * functionality are available, per PSARC 2007/227.
 237  */
 238 /* ARGSUSED */
 239 static int
 240 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
 241 {
 242         smbnode_t       *np;
 243         vnode_t         *vp;
 244         smbfattr_t      fa;
 245         u_int32_t       rights, rightsrcvd;
 246         u_int16_t       fid, oldfid;
 247         int             oldgenid;
 248         struct smb_cred scred;
 249         smbmntinfo_t    *smi;
 250         smb_share_t     *ssp;
 251         cred_t          *oldcr;
 252         int             tmperror;
 253         int             error = 0;
 254 
 255         vp = *vpp;
 256         np = VTOSMB(vp);
 257         smi = VTOSMI(vp);
 258         ssp = smi->smi_share;
 259 
 260         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 261                 return (EIO);
 262 
 263         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 264                 return (EIO);
 265 
 266         if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
 267                 SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
 268                 return (EACCES);
 269         }
 270 
 271         /*
 272          * Get exclusive access to n_fid and related stuff.
 273          * No returns after this until out.
 274          */
 275         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
 276                 return (EINTR);
 277         smb_credinit(&scred, cr);
 278 
 279         /*
 280          * Keep track of the vnode type at first open.
 281          * It may change later, and we need close to do
 282          * cleanup for the type we opened.  Also deny
 283          * open of new types until old type is closed.
 284          * XXX: Per-open instance nodes whould help.
 285          */
 286         if (np->n_ovtype == VNON) {
 287                 ASSERT(np->n_dirrefs == 0);
 288                 ASSERT(np->n_fidrefs == 0);
 289         } else if (np->n_ovtype != vp->v_type) {
 290                 SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
 291                     np->n_ovtype, vp->v_type);
 292                 error = EACCES;
 293                 goto out;
 294         }
 295 
 296         /*
 297          * Directory open.  See smbfs_readvdir()
 298          */
 299         if (vp->v_type == VDIR) {
 300                 if (np->n_dirseq == NULL) {
 301                         /* first open */
 302                         error = smbfs_smb_findopen(np, "*", 1,
 303                             SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
 304                             &scred, &np->n_dirseq);
 305                         if (error != 0)
 306                                 goto out;
 307                 }
 308                 np->n_dirofs = FIRST_DIROFS;
 309                 np->n_dirrefs++;
 310                 goto have_fid;
 311         }
 312 
 313         /*
 314          * If caller specified O_TRUNC/FTRUNC, then be sure to set
 315          * FWRITE (to drive successful setattr(size=0) after open)
 316          */
 317         if (flag & FTRUNC)
 318                 flag |= FWRITE;
 319 
 320         /*
 321          * If we already have it open, and the FID is still valid,
 322          * check whether the rights are sufficient for FID reuse.
 323          */
 324         if (np->n_fidrefs > 0 &&
 325             np->n_vcgenid == ssp->ss_vcgenid) {
 326                 int upgrade = 0;
 327 
 328                 if ((flag & FWRITE) &&
 329                     !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
 330                         upgrade = 1;
 331                 if ((flag & FREAD) &&
 332                     !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
 333                         upgrade = 1;
 334                 if (!upgrade) {
 335                         /*
 336                          *  the existing open is good enough
 337                          */
 338                         np->n_fidrefs++;
 339                         goto have_fid;
 340                 }
 341         }
 342         rights = np->n_fidrefs ? np->n_rights : 0;
 343 
 344         /*
 345          * we always ask for READ_CONTROL so we can always get the
 346          * owner/group IDs to satisfy a stat.  Ditto attributes.
 347          */
 348         rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
 349             SA_RIGHT_FILE_READ_ATTRIBUTES);
 350         if ((flag & FREAD))
 351                 rights |= SA_RIGHT_FILE_READ_DATA;
 352         if ((flag & FWRITE))
 353                 rights |= SA_RIGHT_FILE_WRITE_DATA |
 354                     SA_RIGHT_FILE_APPEND_DATA |
 355                     SA_RIGHT_FILE_WRITE_ATTRIBUTES;
 356 
 357         bzero(&fa, sizeof (fa));
 358         error = smbfs_smb_open(np,
 359             NULL, 0, 0, /* name nmlen xattr */
 360             rights, &scred,
 361             &fid, &rightsrcvd, &fa);
 362         if (error)
 363                 goto out;
 364         smbfs_attrcache_fa(vp, &fa);
 365 
 366         /*
 367          * We have a new FID and access rights.
 368          */
 369         oldfid = np->n_fid;
 370         oldgenid = np->n_vcgenid;
 371         np->n_fid = fid;
 372         np->n_vcgenid = ssp->ss_vcgenid;
 373         np->n_rights = rightsrcvd;
 374         np->n_fidrefs++;
 375         if (np->n_fidrefs > 1 &&
 376             oldgenid == ssp->ss_vcgenid) {
 377                 /*
 378                  * We already had it open (presumably because
 379                  * it was open with insufficient rights.)
 380                  * Close old wire-open.
 381                  */
 382                 tmperror = smbfs_smb_close(ssp,
 383                     oldfid, NULL, &scred);
 384                 if (tmperror)
 385                         SMBVDEBUG("error %d closing %s\n",
 386                             tmperror, np->n_rpath);
 387         }
 388 
 389         /*
 390          * This thread did the open.
 391          * Save our credentials too.
 392          */
 393         mutex_enter(&np->r_statelock);
 394         oldcr = np->r_cred;
 395         np->r_cred = cr;
 396         crhold(cr);
 397         if (oldcr)
 398                 crfree(oldcr);
 399         mutex_exit(&np->r_statelock);
 400 
 401 have_fid:
 402         /*
 403          * Keep track of the vnode type at first open.
 404          * (see comments above)
 405          */
 406         if (np->n_ovtype == VNON)
 407                 np->n_ovtype = vp->v_type;
 408 
 409 out:
 410         smb_credrele(&scred);
 411         smbfs_rw_exit(&np->r_lkserlock);
 412         return (error);
 413 }
 414 
 415 /*ARGSUSED*/
 416 static int
 417 smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
 418         caller_context_t *ct)
 419 {
 420         smbnode_t       *np;
 421         smbmntinfo_t    *smi;
 422         struct smb_cred scred;
 423 
 424         np = VTOSMB(vp);
 425         smi = VTOSMI(vp);
 426 
 427         /*
 428          * Don't "bail out" for VFS_UNMOUNTED here,
 429          * as we want to do cleanup, etc.
 430          */
 431 
 432         /*
 433          * zone_enter(2) prevents processes from changing zones with SMBFS files
 434          * open; if we happen to get here from the wrong zone we can't do
 435          * anything over the wire.
 436          */
 437         if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
 438                 /*
 439                  * We could attempt to clean up locks, except we're sure
 440                  * that the current process didn't acquire any locks on
 441                  * the file: any attempt to lock a file belong to another zone
 442                  * will fail, and one can't lock an SMBFS file and then change
 443                  * zones, as that fails too.
 444                  *
 445                  * Returning an error here is the sane thing to do.  A
 446                  * subsequent call to VN_RELE() which translates to a
 447                  * smbfs_inactive() will clean up state: if the zone of the
 448                  * vnode's origin is still alive and kicking, an async worker
 449                  * thread will handle the request (from the correct zone), and
 450                  * everything (minus the final smbfs_getattr_otw() call) should
 451                  * be OK. If the zone is going away smbfs_async_inactive() will
 452                  * throw away cached pages inline.
 453                  */
 454                 return (EIO);
 455         }
 456 
 457         /*
 458          * If we are using local locking for this filesystem, then
 459          * release all of the SYSV style record locks.  Otherwise,
 460          * we are doing network locking and we need to release all
 461          * of the network locks.  All of the locks held by this
 462          * process on this file are released no matter what the
 463          * incoming reference count is.
 464          */
 465         if (smi->smi_flags & SMI_LLOCK) {
 466                 pid_t pid = ddi_get_pid();
 467                 cleanlocks(vp, pid, 0);
 468                 cleanshares(vp, pid);
 469         }
 470 
 471         /*
 472          * This (passed in) count is the ref. count from the
 473          * user's file_t before the closef call (fio.c).
 474          * We only care when the reference goes away.
 475          */
 476         if (count > 1)
 477                 return (0);
 478 
 479         /*
 480          * Decrement the reference count for the FID
 481          * and possibly do the OtW close.
 482          *
 483          * Exclusive lock for modifying n_fid stuff.
 484          * Don't want this one ever interruptible.
 485          */
 486         (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
 487         smb_credinit(&scred, cr);
 488 
 489         smbfs_rele_fid(np, &scred);
 490 
 491         smb_credrele(&scred);
 492         smbfs_rw_exit(&np->r_lkserlock);
 493 
 494         return (0);
 495 }
 496 
 497 /*
 498  * Helper for smbfs_close.  Decrement the reference count
 499  * for an SMB-level file or directory ID, and when the last
 500  * reference for the fid goes away, do the OtW close.
 501  * Also called in smbfs_inactive (defensive cleanup).
 502  */
 503 static void
 504 smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
 505 {
 506         smb_share_t     *ssp;
 507         cred_t          *oldcr;
 508         struct smbfs_fctx *fctx;
 509         int             error;
 510         uint16_t ofid;
 511 
 512         ssp = np->n_mount->smi_share;
 513         error = 0;
 514 
 515         /* Make sure we serialize for n_dirseq use. */
 516         ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
 517 
 518         /*
 519          * Note that vp->v_type may change if a remote node
 520          * is deleted and recreated as a different type, and
 521          * our getattr may change v_type accordingly.
 522          * Now use n_ovtype to keep track of the v_type
 523          * we had during open (see comments above).
 524          */
 525         switch (np->n_ovtype) {
 526         case VDIR:
 527                 ASSERT(np->n_dirrefs > 0);
 528                 if (--np->n_dirrefs)
 529                         return;
 530                 if ((fctx = np->n_dirseq) != NULL) {
 531                         np->n_dirseq = NULL;
 532                         np->n_dirofs = 0;
 533                         error = smbfs_smb_findclose(fctx, scred);
 534                 }
 535                 break;
 536 
 537         case VREG:
 538                 ASSERT(np->n_fidrefs > 0);
 539                 if (--np->n_fidrefs)
 540                         return;
 541                 if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
 542                         np->n_fid = SMB_FID_UNUSED;
 543                         /* After reconnect, n_fid is invalid */
 544                         if (np->n_vcgenid == ssp->ss_vcgenid) {
 545                                 error = smbfs_smb_close(
 546                                     ssp, ofid, NULL, scred);
 547                         }
 548                 }
 549                 break;
 550 
 551         default:
 552                 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
 553                 break;
 554         }
 555         if (error) {
 556                 SMBVDEBUG("error %d closing %s\n",
 557                     error, np->n_rpath);
 558         }
 559 
 560         /* Allow next open to use any v_type. */
 561         np->n_ovtype = VNON;
 562 
 563         /*
 564          * Other "last close" stuff.
 565          */
 566         mutex_enter(&np->r_statelock);
 567         if (np->n_flag & NATTRCHANGED)
 568                 smbfs_attrcache_rm_locked(np);
 569         oldcr = np->r_cred;
 570         np->r_cred = NULL;
 571         mutex_exit(&np->r_statelock);
 572         if (oldcr != NULL)
 573                 crfree(oldcr);
 574 }
 575 
 576 /* ARGSUSED */
 577 static int
 578 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 579         caller_context_t *ct)
 580 {
 581         struct smb_cred scred;
 582         struct vattr    va;
 583         smbnode_t       *np;
 584         smbmntinfo_t    *smi;
 585         smb_share_t     *ssp;
 586         offset_t        endoff;
 587         ssize_t         past_eof;
 588         int             error;
 589 
 590         np = VTOSMB(vp);
 591         smi = VTOSMI(vp);
 592         ssp = smi->smi_share;
 593 
 594         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 595                 return (EIO);
 596 
 597         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 598                 return (EIO);
 599 
 600         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
 601 
 602         if (vp->v_type != VREG)
 603                 return (EISDIR);
 604 
 605         if (uiop->uio_resid == 0)
 606                 return (0);
 607 
 608         /*
 609          * Like NFS3, just check for 63-bit overflow.
 610          * Our SMB layer takes care to return EFBIG
 611          * when it has to fallback to a 32-bit call.
 612          */
 613         endoff = uiop->uio_loffset + uiop->uio_resid;
 614         if (uiop->uio_loffset < 0 || endoff < 0)
 615                 return (EINVAL);
 616 
 617         /* get vnode attributes from server */
 618         va.va_mask = AT_SIZE | AT_MTIME;
 619         if (error = smbfsgetattr(vp, &va, cr))
 620                 return (error);
 621 
 622         /* Update mtime with mtime from server here? */
 623 
 624         /* if offset is beyond EOF, read nothing */
 625         if (uiop->uio_loffset >= va.va_size)
 626                 return (0);
 627 
 628         /*
 629          * Limit the read to the remaining file size.
 630          * Do this by temporarily reducing uio_resid
 631          * by the amount the lies beyoned the EOF.
 632          */
 633         if (endoff > va.va_size) {
 634                 past_eof = (ssize_t)(endoff - va.va_size);
 635                 uiop->uio_resid -= past_eof;
 636         } else
 637                 past_eof = 0;
 638 
 639         /* Shared lock for n_fid use in smb_rwuio */
 640         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 641                 return (EINTR);
 642         smb_credinit(&scred, cr);
 643 
 644         /* After reconnect, n_fid is invalid */
 645         if (np->n_vcgenid != ssp->ss_vcgenid)
 646                 error = ESTALE;
 647         else
 648                 error = smb_rwuio(ssp, np->n_fid, UIO_READ,
 649                     uiop, &scred, smb_timo_read);
 650 
 651         smb_credrele(&scred);
 652         smbfs_rw_exit(&np->r_lkserlock);
 653 
 654         /* undo adjustment of resid */
 655         uiop->uio_resid += past_eof;
 656 
 657         return (error);
 658 }
 659 
 660 
 661 /* ARGSUSED */
 662 static int
 663 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 664         caller_context_t *ct)
 665 {
 666         struct smb_cred scred;
 667         struct vattr    va;
 668         smbnode_t       *np;
 669         smbmntinfo_t    *smi;
 670         smb_share_t     *ssp;
 671         offset_t        endoff, limit;
 672         ssize_t         past_limit;
 673         int             error, timo;
 674 
 675         np = VTOSMB(vp);
 676         smi = VTOSMI(vp);
 677         ssp = smi->smi_share;
 678 
 679         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 680                 return (EIO);
 681 
 682         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 683                 return (EIO);
 684 
 685         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
 686 
 687         if (vp->v_type != VREG)
 688                 return (EISDIR);
 689 
 690         if (uiop->uio_resid == 0)
 691                 return (0);
 692 
 693         /*
 694          * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
 695          */
 696         if (ioflag & (FAPPEND | FSYNC)) {
 697                 if (np->n_flag & NMODIFIED) {
 698                         smbfs_attrcache_remove(np);
 699                         /* XXX: smbfs_vinvalbuf? */
 700                 }
 701         }
 702         if (ioflag & FAPPEND) {
 703                 /*
 704                  * File size can be changed by another client
 705                  */
 706                 va.va_mask = AT_SIZE;
 707                 if (error = smbfsgetattr(vp, &va, cr))
 708                         return (error);
 709                 uiop->uio_loffset = va.va_size;
 710         }
 711 
 712         /*
 713          * Like NFS3, just check for 63-bit overflow.
 714          */
 715         endoff = uiop->uio_loffset + uiop->uio_resid;
 716         if (uiop->uio_loffset < 0 || endoff < 0)
 717                 return (EINVAL);
 718 
 719         /*
 720          * Check to make sure that the process will not exceed
 721          * its limit on file size.  It is okay to write up to
 722          * the limit, but not beyond.  Thus, the write which
 723          * reaches the limit will be short and the next write
 724          * will return an error.
 725          *
 726          * So if we're starting at or beyond the limit, EFBIG.
 727          * Otherwise, temporarily reduce resid to the amount
 728          * the falls after the limit.
 729          */
 730         limit = uiop->uio_llimit;
 731         if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
 732                 limit = MAXOFFSET_T;
 733         if (uiop->uio_loffset >= limit)
 734                 return (EFBIG);
 735         if (endoff > limit) {
 736                 past_limit = (ssize_t)(endoff - limit);
 737                 uiop->uio_resid -= past_limit;
 738         } else
 739                 past_limit = 0;
 740 
 741         /* Timeout: longer for append. */
 742         timo = smb_timo_write;
 743         if (endoff > np->r_size)
 744                 timo = smb_timo_append;
 745 
 746         /* Shared lock for n_fid use in smb_rwuio */
 747         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 748                 return (EINTR);
 749         smb_credinit(&scred, cr);
 750 
 751         /* After reconnect, n_fid is invalid */
 752         if (np->n_vcgenid != ssp->ss_vcgenid)
 753                 error = ESTALE;
 754         else
 755                 error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
 756                     uiop, &scred, timo);
 757 
 758         if (error == 0) {
 759                 mutex_enter(&np->r_statelock);
 760                 np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
 761                 if (uiop->uio_loffset > (offset_t)np->r_size)
 762                         np->r_size = (len_t)uiop->uio_loffset;
 763                 mutex_exit(&np->r_statelock);
 764                 if (ioflag & (FSYNC|FDSYNC)) {
 765                         /* Don't error the I/O if this fails. */
 766                         (void) smbfs_smb_flush(np, &scred);
 767                 }
 768         }
 769 
 770         smb_credrele(&scred);
 771         smbfs_rw_exit(&np->r_lkserlock);
 772 
 773         /* undo adjustment of resid */
 774         uiop->uio_resid += past_limit;
 775 
 776         return (error);
 777 }
 778 
 779 
 780 /* ARGSUSED */
 781 static int
 782 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
 783         cred_t *cr, int *rvalp, caller_context_t *ct)
 784 {
 785         int             error;
 786         smbmntinfo_t    *smi;
 787 
 788         smi = VTOSMI(vp);
 789 
 790         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 791                 return (EIO);
 792 
 793         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 794                 return (EIO);
 795 
 796         switch (cmd) {
 797                 /* First three from ZFS. XXX - need these? */
 798 
 799         case _FIOFFS:
 800                 error = smbfs_fsync(vp, 0, cr, ct);
 801                 break;
 802 
 803                 /*
 804                  * The following two ioctls are used by bfu.
 805                  * Silently ignore to avoid bfu errors.
 806                  */
 807         case _FIOGDIO:
 808         case _FIOSDIO:
 809                 error = 0;
 810                 break;
 811 
 812 #ifdef NOT_YET  /* XXX - from the NFS code. */
 813         case _FIODIRECTIO:
 814                 error = smbfs_directio(vp, (int)arg, cr);
 815 #endif
 816 
 817                 /*
 818                  * Allow get/set with "raw" security descriptor (SD) data.
 819                  * Useful for testing, diagnosing idmap problems, etc.
 820                  */
 821         case SMBFSIO_GETSD:
 822                 error = smbfs_acl_iocget(vp, arg, flag, cr);
 823                 break;
 824 
 825         case SMBFSIO_SETSD:
 826                 error = smbfs_acl_iocset(vp, arg, flag, cr);
 827                 break;
 828 
 829         default:
 830                 error = ENOTTY;
 831                 break;
 832         }
 833 
 834         return (error);
 835 }
 836 
 837 
 838 /*
 839  * Return either cached or remote attributes. If get remote attr
 840  * use them to check and invalidate caches, then cache the new attributes.
 841  *
 842  * XXX
 843  * This op should eventually support PSARC 2007/315, Extensible Attribute
 844  * Interfaces, for richer metadata.
 845  */
 846 /* ARGSUSED */
 847 static int
 848 smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
 849         caller_context_t *ct)
 850 {
 851         smbnode_t *np;
 852         smbmntinfo_t *smi;
 853 
 854         smi = VTOSMI(vp);
 855 
 856         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 857                 return (EIO);
 858 
 859         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
 860                 return (EIO);
 861 
 862         /*
 863          * If it has been specified that the return value will
 864          * just be used as a hint, and we are only being asked
 865          * for size, fsid or rdevid, then return the client's
 866          * notion of these values without checking to make sure
 867          * that the attribute cache is up to date.
 868          * The whole point is to avoid an over the wire GETATTR
 869          * call.
 870          */
 871         np = VTOSMB(vp);
 872         if (flags & ATTR_HINT) {
 873                 if (vap->va_mask ==
 874                     (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
 875                         mutex_enter(&np->r_statelock);
 876                         if (vap->va_mask | AT_SIZE)
 877                                 vap->va_size = np->r_size;
 878                         if (vap->va_mask | AT_FSID)
 879                                 vap->va_fsid = vp->v_vfsp->vfs_dev;
 880                         if (vap->va_mask | AT_RDEV)
 881                                 vap->va_rdev = vp->v_rdev;
 882                         mutex_exit(&np->r_statelock);
 883                         return (0);
 884                 }
 885         }
 886 
 887         return (smbfsgetattr(vp, vap, cr));
 888 }
 889 
 890 /* smbfsgetattr() in smbfs_client.c */
 891 
 892 /*
 893  * XXX
 894  * This op should eventually support PSARC 2007/315, Extensible Attribute
 895  * Interfaces, for richer metadata.
 896  */
 897 /*ARGSUSED4*/
 898 static int
 899 smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
 900                 caller_context_t *ct)
 901 {
 902         vfs_t           *vfsp;
 903         smbmntinfo_t    *smi;
 904         int             error;
 905         uint_t          mask;
 906         struct vattr    oldva;
 907 
 908         vfsp = vp->v_vfsp;
 909         smi = VFTOSMI(vfsp);
 910 
 911         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
 912                 return (EIO);
 913 
 914         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
 915                 return (EIO);
 916 
 917         mask = vap->va_mask;
 918         if (mask & AT_NOSET)
 919                 return (EINVAL);
 920 
 921         if (vfsp->vfs_flag & VFS_RDONLY)
 922                 return (EROFS);
 923 
 924         /*
 925          * This is a _local_ access check so that only the owner of
 926          * this mount can set attributes.  With ACLs enabled, the
 927          * file owner can be different from the mount owner, and we
 928          * need to check the _mount_ owner here.  See _access_rwx
 929          */
 930         bzero(&oldva, sizeof (oldva));
 931         oldva.va_mask = AT_TYPE | AT_MODE;
 932         error = smbfsgetattr(vp, &oldva, cr);
 933         if (error)
 934                 return (error);
 935         oldva.va_mask |= AT_UID | AT_GID;
 936         oldva.va_uid = smi->smi_uid;
 937         oldva.va_gid = smi->smi_gid;
 938 
 939         error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
 940             smbfs_accessx, vp);
 941         if (error)
 942                 return (error);
 943 
 944         if (mask & (AT_UID | AT_GID)) {
 945                 if (smi->smi_flags & SMI_ACL)
 946                         error = smbfs_acl_setids(vp, vap, cr);
 947                 else
 948                         error = ENOSYS;
 949                 if (error != 0) {
 950                         SMBVDEBUG("error %d seting UID/GID on %s",
 951                             error, VTOSMB(vp)->n_rpath);
 952                         /*
 953                          * It might be more correct to return the
 954                          * error here, but that causes complaints
 955                          * when root extracts a cpio archive, etc.
 956                          * So ignore this error, and go ahead with
 957                          * the rest of the setattr work.
 958                          */
 959                 }
 960         }
 961 
 962         return (smbfssetattr(vp, vap, flags, cr));
 963 }
 964 
 965 /*
 966  * Mostly from Darwin smbfs_setattr()
 967  * but then modified a lot.
 968  */
 969 /* ARGSUSED */
 970 static int
 971 smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
 972 {
 973         int             error = 0;
 974         smbnode_t       *np = VTOSMB(vp);
 975         uint_t          mask = vap->va_mask;
 976         struct timespec *mtime, *atime;
 977         struct smb_cred scred;
 978         int             cerror, modified = 0;
 979         unsigned short  fid;
 980         int have_fid = 0;
 981         uint32_t rights = 0;
 982 
 983         ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
 984 
 985         /*
 986          * There are no settable attributes on the XATTR dir,
 987          * so just silently ignore these.  On XATTR files,
 988          * you can set the size but nothing else.
 989          */
 990         if (vp->v_flag & V_XATTRDIR)
 991                 return (0);
 992         if (np->n_flag & N_XATTR) {
 993                 if (mask & AT_TIMES)
 994                         SMBVDEBUG("ignore set time on xattr\n");
 995                 mask &= AT_SIZE;
 996         }
 997 
 998         /*
 999          * If our caller is trying to set multiple attributes, they
1000          * can make no assumption about what order they are done in.
1001          * Here we try to do them in order of decreasing likelihood
1002          * of failure, just to minimize the chance we'll wind up
1003          * with a partially complete request.
1004          */
1005 
1006         /* Shared lock for (possible) n_fid use. */
1007         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1008                 return (EINTR);
1009         smb_credinit(&scred, cr);
1010 
1011         /*
1012          * Will we need an open handle for this setattr?
1013          * If so, what rights will we need?
1014          */
1015         if (mask & (AT_ATIME | AT_MTIME)) {
1016                 rights |=
1017                     SA_RIGHT_FILE_WRITE_ATTRIBUTES;
1018         }
1019         if (mask & AT_SIZE) {
1020                 rights |=
1021                     SA_RIGHT_FILE_WRITE_DATA |
1022                     SA_RIGHT_FILE_APPEND_DATA;
1023         }
1024 
1025         /*
1026          * Only SIZE really requires a handle, but it's
1027          * simpler and more reliable to set via a handle.
1028          * Some servers like NT4 won't set times by path.
1029          * Also, we're usually setting everything anyway.
1030          */
1031         if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) {
1032                 error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
1033                 if (error) {
1034                         SMBVDEBUG("error %d opening %s\n",
1035                             error, np->n_rpath);
1036                         goto out;
1037                 }
1038                 have_fid = 1;
1039         }
1040 
1041         /*
1042          * If the server supports the UNIX extensions, right here is where
1043          * we'd support changes to uid, gid, mode, and possibly va_flags.
1044          * For now we claim to have made any such changes.
1045          */
1046 
1047         if (mask & AT_SIZE) {
1048                 /*
1049                  * If the new file size is less than what the client sees as
1050                  * the file size, then just change the size and invalidate
1051                  * the pages.
1052                  * I am commenting this code at present because the function
1053                  * smbfs_putapage() is not yet implemented.
1054                  */
1055 
1056                 /*
1057                  * Set the file size to vap->va_size.
1058                  */
1059                 ASSERT(have_fid);
1060                 error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
1061                 if (error) {
1062                         SMBVDEBUG("setsize error %d file %s\n",
1063                             error, np->n_rpath);
1064                 } else {
1065                         /*
1066                          * Darwin had code here to zero-extend.
1067                          * Tests indicate the server will zero-fill,
1068                          * so looks like we don't need to do this.
1069                          * Good thing, as this could take forever.
1070                          *
1071                          * XXX: Reportedly, writing one byte of zero
1072                          * at the end offset avoids problems here.
1073                          */
1074                         mutex_enter(&np->r_statelock);
1075                         np->r_size = vap->va_size;
1076                         mutex_exit(&np->r_statelock);
1077                         modified = 1;
1078                 }
1079         }
1080 
1081         /*
1082          * XXX: When Solaris has create_time, set that too.
1083          * Note: create_time is different from ctime.
1084          */
1085         mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
1086         atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
1087 
1088         if (mtime || atime) {
1089                 /*
1090                  * Always use the handle-based set attr call now.
1091                  * Not trying to set DOS attributes here so pass zero.
1092                  */
1093                 ASSERT(have_fid);
1094                 error = smbfs_smb_setfattr(np, fid,
1095                     0, mtime, atime, &scred);
1096                 if (error) {
1097                         SMBVDEBUG("set times error %d file %s\n",
1098                             error, np->n_rpath);
1099                 } else {
1100                         modified = 1;
1101                 }
1102         }
1103 
1104 out:
1105         if (modified) {
1106                 /*
1107                  * Invalidate attribute cache in case the server
1108                  * doesn't set exactly the attributes we asked.
1109                  */
1110                 smbfs_attrcache_remove(np);
1111         }
1112 
1113         if (have_fid) {
1114                 cerror = smbfs_smb_tmpclose(np, fid, &scred);
1115                 if (cerror)
1116                         SMBVDEBUG("error %d closing %s\n",
1117                             cerror, np->n_rpath);
1118         }
1119 
1120         smb_credrele(&scred);
1121         smbfs_rw_exit(&np->r_lkserlock);
1122 
1123         return (error);
1124 }
1125 
1126 /*
1127  * smbfs_access_rwx()
1128  * Common function for smbfs_access, etc.
1129  *
1130  * The security model implemented by the FS is unusual
1131  * due to the current "single user mounts" restriction:
1132  * All access under a given mount point uses the CIFS
1133  * credentials established by the owner of the mount.
1134  *
1135  * Most access checking is handled by the CIFS server,
1136  * but we need sufficient Unix access checks here to
1137  * prevent other local Unix users from having access
1138  * to objects under this mount that the uid/gid/mode
1139  * settings in the mount would not allow.
1140  *
1141  * With this model, there is a case where we need the
1142  * ability to do an access check before we have the
1143  * vnode for an object.  This function takes advantage
1144  * of the fact that the uid/gid/mode is per mount, and
1145  * avoids the need for a vnode.
1146  *
1147  * We still (sort of) need a vnode when we call
1148  * secpolicy_vnode_access, but that only uses
1149  * the vtype field, so we can use a pair of fake
1150  * vnodes that have only v_type filled in.
1151  *
1152  * XXX: Later, add a new secpolicy_vtype_access()
1153  * that takes the vtype instead of a vnode, and
1154  * get rid of the tmpl_vxxx fake vnodes below.
1155  */
1156 static int
1157 smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
1158 {
1159         /* See the secpolicy call below. */
1160         static const vnode_t tmpl_vdir = { .v_type = VDIR };
1161         static const vnode_t tmpl_vreg = { .v_type = VREG };
1162         vattr_t         va;
1163         vnode_t         *tvp;
1164         struct smbmntinfo *smi = VFTOSMI(vfsp);
1165         int shift = 0;
1166 
1167         /*
1168          * Build our (fabricated) vnode attributes.
1169          * XXX: Could make these templates in the
1170          * per-mount struct and use them here.
1171          */
1172         bzero(&va, sizeof (va));
1173         va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1174         va.va_type = vtype;
1175         va.va_mode = (vtype == VDIR) ?
1176             smi->smi_dmode : smi->smi_fmode;
1177         va.va_uid = smi->smi_uid;
1178         va.va_gid = smi->smi_gid;
1179 
1180         /*
1181          * Disallow write attempts on read-only file systems,
1182          * unless the file is a device or fifo node.  Note:
1183          * Inline vn_is_readonly and IS_DEVVP here because
1184          * we may not have a vnode ptr.  Original expr. was:
1185          * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1186          */
1187         if ((mode & VWRITE) &&
1188             (vfsp->vfs_flag & VFS_RDONLY) &&
1189             !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1190                 return (EROFS);
1191 
1192         /*
1193          * Disallow attempts to access mandatory lock files.
1194          * Similarly, expand MANDLOCK here.
1195          * XXX: not sure we need this.
1196          */
1197         if ((mode & (VWRITE | VREAD | VEXEC)) &&
1198             va.va_type == VREG && MANDMODE(va.va_mode))
1199                 return (EACCES);
1200 
1201         /*
1202          * Access check is based on only
1203          * one of owner, group, public.
1204          * If not owner, then check group.
1205          * If not a member of the group,
1206          * then check public access.
1207          */
1208         if (crgetuid(cr) != va.va_uid) {
1209                 shift += 3;
1210                 if (!groupmember(va.va_gid, cr))
1211                         shift += 3;
1212         }
1213 
1214         /*
1215          * We need a vnode for secpolicy_vnode_access,
1216          * but the only thing it looks at is v_type,
1217          * so pass one of the templates above.
1218          */
1219         tvp = (va.va_type == VDIR) ?
1220             (vnode_t *)&tmpl_vdir :
1221             (vnode_t *)&tmpl_vreg;
1222 
1223         return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1224             va.va_mode << shift, mode));
1225 }
1226 
1227 /*
1228  * See smbfs_setattr
1229  */
1230 static int
1231 smbfs_accessx(void *arg, int mode, cred_t *cr)
1232 {
1233         vnode_t *vp = arg;
1234         /*
1235          * Note: The caller has checked the current zone,
1236          * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1237          */
1238         return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1239 }
1240 
1241 /*
1242  * XXX
1243  * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1244  */
1245 /* ARGSUSED */
1246 static int
1247 smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1248 {
1249         vfs_t           *vfsp;
1250         smbmntinfo_t    *smi;
1251 
1252         vfsp = vp->v_vfsp;
1253         smi = VFTOSMI(vfsp);
1254 
1255         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1256                 return (EIO);
1257 
1258         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1259                 return (EIO);
1260 
1261         return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1262 }
1263 
1264 
1265 /*
1266  * Flush local dirty pages to stable storage on the server.
1267  *
1268  * If FNODSYNC is specified, then there is nothing to do because
1269  * metadata changes are not cached on the client before being
1270  * sent to the server.
1271  */
1272 /* ARGSUSED */
1273 static int
1274 smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1275 {
1276         int             error = 0;
1277         smbmntinfo_t    *smi;
1278         smbnode_t       *np;
1279         struct smb_cred scred;
1280 
1281         np = VTOSMB(vp);
1282         smi = VTOSMI(vp);
1283 
1284         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1285                 return (EIO);
1286 
1287         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1288                 return (EIO);
1289 
1290         if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1291                 return (0);
1292 
1293         if ((syncflag & (FSYNC|FDSYNC)) == 0)
1294                 return (0);
1295 
1296         /* Shared lock for n_fid use in _flush */
1297         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
1298                 return (EINTR);
1299         smb_credinit(&scred, cr);
1300 
1301         error = smbfs_smb_flush(np, &scred);
1302 
1303         smb_credrele(&scred);
1304         smbfs_rw_exit(&np->r_lkserlock);
1305 
1306         return (error);
1307 }
1308 
1309 /*
1310  * Last reference to vnode went away.
1311  */
1312 /* ARGSUSED */
1313 static void
1314 smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1315 {
1316         smbnode_t       *np;
1317         struct smb_cred scred;
1318 
1319         /*
1320          * Don't "bail out" for VFS_UNMOUNTED here,
1321          * as we want to do cleanup, etc.
1322          * See also pcfs_inactive
1323          */
1324 
1325         np = VTOSMB(vp);
1326 
1327         /*
1328          * If this is coming from the wrong zone, we let someone in the right
1329          * zone take care of it asynchronously.  We can get here due to
1330          * VN_RELE() being called from pageout() or fsflush().  This call may
1331          * potentially turn into an expensive no-op if, for instance, v_count
1332          * gets incremented in the meantime, but it's still correct.
1333          */
1334 
1335         /*
1336          * Defend against the possibility that higher-level callers
1337          * might not correctly balance open and close calls.  If we
1338          * get here with open references remaining, it means there
1339          * was a missing VOP_CLOSE somewhere.  If that happens, do
1340          * the close here so we don't "leak" FIDs on the server.
1341          *
1342          * Exclusive lock for modifying n_fid stuff.
1343          * Don't want this one ever interruptible.
1344          */
1345         (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
1346         smb_credinit(&scred, cr);
1347 
1348         switch (np->n_ovtype) {
1349         case VNON:
1350                 /* not open (OK) */
1351                 break;
1352 
1353         case VDIR:
1354                 if (np->n_dirrefs == 0)
1355                         break;
1356                 SMBVDEBUG("open dir: refs %d path %s\n",
1357                     np->n_dirrefs, np->n_rpath);
1358                 /* Force last close. */
1359                 np->n_dirrefs = 1;
1360                 smbfs_rele_fid(np, &scred);
1361                 break;
1362 
1363         case VREG:
1364                 if (np->n_fidrefs == 0)
1365                         break;
1366                 SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
1367                     np->n_fidrefs, np->n_fid, np->n_rpath);
1368                 /* Force last close. */
1369                 np->n_fidrefs = 1;
1370                 smbfs_rele_fid(np, &scred);
1371                 break;
1372 
1373         default:
1374                 SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
1375                 np->n_ovtype = VNON;
1376                 break;
1377         }
1378 
1379         smb_credrele(&scred);
1380         smbfs_rw_exit(&np->r_lkserlock);
1381 
1382         smbfs_addfree(np);
1383 }
1384 
1385 /*
1386  * Remote file system operations having to do with directory manipulation.
1387  */
1388 /* ARGSUSED */
1389 static int
1390 smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1391         int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1392         int *direntflags, pathname_t *realpnp)
1393 {
1394         vfs_t           *vfs;
1395         smbmntinfo_t    *smi;
1396         smbnode_t       *dnp;
1397         int             error;
1398 
1399         vfs = dvp->v_vfsp;
1400         smi = VFTOSMI(vfs);
1401 
1402         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1403                 return (EPERM);
1404 
1405         if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
1406                 return (EIO);
1407 
1408         dnp = VTOSMB(dvp);
1409 
1410         /*
1411          * Are we looking up extended attributes?  If so, "dvp" is
1412          * the file or directory for which we want attributes, and
1413          * we need a lookup of the (faked up) attribute directory
1414          * before we lookup the rest of the path.
1415          */
1416         if (flags & LOOKUP_XATTR) {
1417                 /*
1418                  * Require the xattr mount option.
1419                  */
1420                 if ((vfs->vfs_flag & VFS_XATTR) == 0)
1421                         return (EINVAL);
1422 
1423                 error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
1424                 return (error);
1425         }
1426 
1427         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
1428                 return (EINTR);
1429 
1430         error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1431 
1432         smbfs_rw_exit(&dnp->r_rwlock);
1433 
1434         return (error);
1435 }
1436 
1437 /* ARGSUSED */
1438 static int
1439 smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
1440         int cache_ok, caller_context_t *ct)
1441 {
1442         int             error;
1443         int             supplen; /* supported length */
1444         vnode_t         *vp;
1445         smbnode_t       *np;
1446         smbnode_t       *dnp;
1447         smbmntinfo_t    *smi;
1448         /* struct smb_vc        *vcp; */
1449         const char      *ill;
1450         const char      *name = (const char *)nm;
1451         int             nmlen = strlen(nm);
1452         int             rplen;
1453         struct smb_cred scred;
1454         struct smbfattr fa;
1455 
1456         smi = VTOSMI(dvp);
1457         dnp = VTOSMB(dvp);
1458 
1459         ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
1460 
1461 #ifdef NOT_YET
1462         vcp = SSTOVC(smi->smi_share);
1463 
1464         /* XXX: Should compute this once and store it in smbmntinfo_t */
1465         supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1466 #else
1467         supplen = 255;
1468 #endif
1469 
1470         /*
1471          * RWlock must be held, either reader or writer.
1472          * XXX: Can we check without looking directly
1473          * inside the struct smbfs_rwlock_t?
1474          */
1475         ASSERT(dnp->r_rwlock.count != 0);
1476 
1477         /*
1478          * If lookup is for "", just return dvp.
1479          * No need to perform any access checks.
1480          */
1481         if (nmlen == 0) {
1482                 VN_HOLD(dvp);
1483                 *vpp = dvp;
1484                 return (0);
1485         }
1486 
1487         /*
1488          * Can't do lookups in non-directories.
1489          */
1490         if (dvp->v_type != VDIR)
1491                 return (ENOTDIR);
1492 
1493         /*
1494          * Need search permission in the directory.
1495          */
1496         error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1497         if (error)
1498                 return (error);
1499 
1500         /*
1501          * If lookup is for ".", just return dvp.
1502          * Access check was done above.
1503          */
1504         if (nmlen == 1 && name[0] == '.') {
1505                 VN_HOLD(dvp);
1506                 *vpp = dvp;
1507                 return (0);
1508         }
1509 
1510         /*
1511          * Now some sanity checks on the name.
1512          * First check the length.
1513          */
1514         if (nmlen > supplen)
1515                 return (ENAMETOOLONG);
1516 
1517         /*
1518          * Avoid surprises with characters that are
1519          * illegal in Windows file names.
1520          * Todo: CATIA mappings  XXX
1521          */
1522         ill = illegal_chars;
1523         if (dnp->n_flag & N_XATTR)
1524                 ill++; /* allow colon */
1525         if (strpbrk(nm, ill))
1526                 return (EINVAL);
1527 
1528         /*
1529          * Special handling for lookup of ".."
1530          *
1531          * We keep full pathnames (as seen on the server)
1532          * so we can just trim off the last component to
1533          * get the full pathname of the parent.  Note:
1534          * We don't actually copy and modify, but just
1535          * compute the trimmed length and pass that with
1536          * the current dir path (not null terminated).
1537          *
1538          * We don't go over-the-wire to get attributes
1539          * for ".." because we know it's a directory,
1540          * and we can just leave the rest "stale"
1541          * until someone does a getattr.
1542          */
1543         if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1544                 if (dvp->v_flag & VROOT) {
1545                         /*
1546                          * Already at the root.  This can happen
1547                          * with directory listings at the root,
1548                          * which lookup "." and ".." to get the
1549                          * inode numbers.  Let ".." be the same
1550                          * as "." in the FS root.
1551                          */
1552                         VN_HOLD(dvp);
1553                         *vpp = dvp;
1554                         return (0);
1555                 }
1556 
1557                 /*
1558                  * Special case for XATTR directory
1559                  */
1560                 if (dvp->v_flag & V_XATTRDIR) {
1561                         error = smbfs_xa_parent(dvp, vpp);
1562                         return (error);
1563                 }
1564 
1565                 /*
1566                  * Find the parent path length.
1567                  */
1568                 rplen = dnp->n_rplen;
1569                 ASSERT(rplen > 0);
1570                 while (--rplen >= 0) {
1571                         if (dnp->n_rpath[rplen] == '\\')
1572                                 break;
1573                 }
1574                 if (rplen <= 0) {
1575                         /* Found our way to the root. */
1576                         vp = SMBTOV(smi->smi_root);
1577                         VN_HOLD(vp);
1578                         *vpp = vp;
1579                         return (0);
1580                 }
1581                 np = smbfs_node_findcreate(smi,
1582                     dnp->n_rpath, rplen, NULL, 0, 0,
1583                     &smbfs_fattr0); /* force create */
1584                 ASSERT(np != NULL);
1585                 vp = SMBTOV(np);
1586                 vp->v_type = VDIR;
1587 
1588                 /* Success! */
1589                 *vpp = vp;
1590                 return (0);
1591         }
1592 
1593         /*
1594          * Normal lookup of a name under this directory.
1595          * Note we handled "", ".", ".." above.
1596          */
1597         if (cache_ok) {
1598                 /*
1599                  * The caller indicated that it's OK to use a
1600                  * cached result for this lookup, so try to
1601                  * reclaim a node from the smbfs node cache.
1602                  */
1603                 error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
1604                 if (error)
1605                         return (error);
1606                 if (vp != NULL) {
1607                         /* hold taken in lookup_cache */
1608                         *vpp = vp;
1609                         return (0);
1610                 }
1611         }
1612 
1613         /*
1614          * OK, go over-the-wire to get the attributes,
1615          * then create the node.
1616          */
1617         smb_credinit(&scred, cr);
1618         /* Note: this can allocate a new "name" */
1619         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1620         smb_credrele(&scred);
1621         if (error == ENOTDIR) {
1622                 /*
1623                  * Lookup failed because this directory was
1624                  * removed or renamed by another client.
1625                  * Remove any cached attributes under it.
1626                  */
1627                 smbfs_attrcache_remove(dnp);
1628                 smbfs_attrcache_prune(dnp);
1629         }
1630         if (error)
1631                 goto out;
1632 
1633         error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1634         if (error)
1635                 goto out;
1636 
1637         /* Success! */
1638         *vpp = vp;
1639 
1640 out:
1641         /* smbfs_smb_lookup may have allocated name. */
1642         if (name != nm)
1643                 smbfs_name_free(name, nmlen);
1644 
1645         return (error);
1646 }
1647 
1648 /*
1649  * smbfslookup_cache
1650  *
1651  * Try to reclaim a node from the smbfs node cache.
1652  * Some statistics for DEBUG.
1653  *
1654  * This mechanism lets us avoid many of the five (or more)
1655  * OtW lookup calls per file seen with "ls -l" if we search
1656  * the smbfs node cache for recently inactive(ated) nodes.
1657  */
1658 #ifdef DEBUG
1659 int smbfs_lookup_cache_calls = 0;
1660 int smbfs_lookup_cache_error = 0;
1661 int smbfs_lookup_cache_miss = 0;
1662 int smbfs_lookup_cache_stale = 0;
1663 int smbfs_lookup_cache_hits = 0;
1664 #endif /* DEBUG */
1665 
1666 /* ARGSUSED */
1667 static int
1668 smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
1669         vnode_t **vpp, cred_t *cr)
1670 {
1671         struct vattr va;
1672         smbnode_t *dnp;
1673         smbnode_t *np;
1674         vnode_t *vp;
1675         int error;
1676         char sep;
1677 
1678         dnp = VTOSMB(dvp);
1679         *vpp = NULL;
1680 
1681 #ifdef DEBUG
1682         smbfs_lookup_cache_calls++;
1683 #endif
1684 
1685         /*
1686          * First make sure we can get attributes for the
1687          * directory.  Cached attributes are OK here.
1688          * If we removed or renamed the directory, this
1689          * will return ENOENT.  If someone else removed
1690          * this directory or file, we'll find out when we
1691          * try to open or get attributes.
1692          */
1693         va.va_mask = AT_TYPE | AT_MODE;
1694         error = smbfsgetattr(dvp, &va, cr);
1695         if (error) {
1696 #ifdef DEBUG
1697                 smbfs_lookup_cache_error++;
1698 #endif
1699                 return (error);
1700         }
1701 
1702         /*
1703          * Passing NULL smbfattr here so we will
1704          * just look, not create.
1705          */
1706         sep = SMBFS_DNP_SEP(dnp);
1707         np = smbfs_node_findcreate(dnp->n_mount,
1708             dnp->n_rpath, dnp->n_rplen,
1709             nm, nmlen, sep, NULL);
1710         if (np == NULL) {
1711 #ifdef DEBUG
1712                 smbfs_lookup_cache_miss++;
1713 #endif
1714                 return (0);
1715         }
1716 
1717         /*
1718          * Found it.  Attributes still valid?
1719          */
1720         vp = SMBTOV(np);
1721         if (np->r_attrtime <= gethrtime()) {
1722                 /* stale */
1723 #ifdef DEBUG
1724                 smbfs_lookup_cache_stale++;
1725 #endif
1726                 VN_RELE(vp);
1727                 return (0);
1728         }
1729 
1730         /*
1731          * Success!
1732          * Caller gets hold from smbfs_node_findcreate
1733          */
1734 #ifdef DEBUG
1735         smbfs_lookup_cache_hits++;
1736 #endif
1737         *vpp = vp;
1738         return (0);
1739 }
1740 
1741 /*
1742  * XXX
1743  * vsecattr_t is new to build 77, and we need to eventually support
1744  * it in order to create an ACL when an object is created.
1745  *
1746  * This op should support the new FIGNORECASE flag for case-insensitive
1747  * lookups, per PSARC 2007/244.
1748  */
1749 /* ARGSUSED */
1750 static int
1751 smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1752         int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1753         vsecattr_t *vsecp)
1754 {
1755         int             error;
1756         int             cerror;
1757         vfs_t           *vfsp;
1758         vnode_t         *vp;
1759 #ifdef NOT_YET
1760         smbnode_t       *np;
1761 #endif
1762         smbnode_t       *dnp;
1763         smbmntinfo_t    *smi;
1764         struct vattr    vattr;
1765         struct smbfattr fattr;
1766         struct smb_cred scred;
1767         const char *name = (const char *)nm;
1768         int             nmlen = strlen(nm);
1769         uint32_t        disp;
1770         uint16_t        fid;
1771         int             xattr;
1772 
1773         vfsp = dvp->v_vfsp;
1774         smi = VFTOSMI(vfsp);
1775         dnp = VTOSMB(dvp);
1776         vp = NULL;
1777 
1778         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
1779                 return (EPERM);
1780 
1781         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1782                 return (EIO);
1783 
1784         /*
1785          * Note: this may break mknod(2) calls to create a directory,
1786          * but that's obscure use.  Some other filesystems do this.
1787          * XXX: Later, redirect VDIR type here to _mkdir.
1788          */
1789         if (va->va_type != VREG)
1790                 return (EINVAL);
1791 
1792         /*
1793          * If the pathname is "", just use dvp, no checks.
1794          * Do this outside of the rwlock (like zfs).
1795          */
1796         if (nmlen == 0) {
1797                 VN_HOLD(dvp);
1798                 *vpp = dvp;
1799                 return (0);
1800         }
1801 
1802         /* Don't allow "." or ".." through here. */
1803         if ((nmlen == 1 && name[0] == '.') ||
1804             (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1805                 return (EISDIR);
1806 
1807         /*
1808          * We make a copy of the attributes because the caller does not
1809          * expect us to change what va points to.
1810          */
1811         vattr = *va;
1812 
1813         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1814                 return (EINTR);
1815         smb_credinit(&scred, cr);
1816 
1817         /*
1818          * XXX: Do we need r_lkserlock too?
1819          * No use of any shared fid or fctx...
1820          */
1821 
1822         /*
1823          * NFS needs to go over the wire, just to be sure whether the
1824          * file exists or not.  Using a cached result is dangerous in
1825          * this case when making a decision regarding existence.
1826          *
1827          * The SMB protocol does NOT really need to go OTW here
1828          * thanks to the expressive NTCREATE disposition values.
1829          * Unfortunately, to do Unix access checks correctly,
1830          * we need to know if the object already exists.
1831          * When the object does not exist, we need VWRITE on
1832          * the directory.  Note: smbfslookup() checks VEXEC.
1833          */
1834         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1835         if (error == 0) {
1836                 /*
1837                  * The file already exists.  Error?
1838                  * NB: have a hold from smbfslookup
1839                  */
1840                 if (exclusive == EXCL) {
1841                         error = EEXIST;
1842                         VN_RELE(vp);
1843                         goto out;
1844                 }
1845                 /*
1846                  * Verify requested access.
1847                  */
1848                 error = smbfs_access(vp, mode, 0, cr, ct);
1849                 if (error) {
1850                         VN_RELE(vp);
1851                         goto out;
1852                 }
1853 
1854                 /*
1855                  * Truncate (if requested).
1856                  */
1857                 if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
1858                         vattr.va_mask = AT_SIZE;
1859                         error = smbfssetattr(vp, &vattr, 0, cr);
1860                         if (error) {
1861                                 VN_RELE(vp);
1862                                 goto out;
1863                         }
1864                 }
1865                 /* Success! */
1866 #ifdef NOT_YET
1867                 vnevent_create(vp, ct);
1868 #endif
1869                 *vpp = vp;
1870                 goto out;
1871         }
1872 
1873         /*
1874          * The file did not exist.  Need VWRITE in the directory.
1875          */
1876         error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1877         if (error)
1878                 goto out;
1879 
1880         /*
1881          * Now things get tricky.  We also need to check the
1882          * requested open mode against the file we may create.
1883          * See comments at smbfs_access_rwx
1884          */
1885         error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1886         if (error)
1887                 goto out;
1888 
1889         /*
1890          * Now the code derived from Darwin,
1891          * but with greater use of NT_CREATE
1892          * disposition options.  Much changed.
1893          *
1894          * Create (or open) a new child node.
1895          * Note we handled "." and ".." above.
1896          */
1897 
1898         if (exclusive == EXCL)
1899                 disp = NTCREATEX_DISP_CREATE;
1900         else {
1901                 /* Truncate regular files if requested. */
1902                 if ((va->va_type == VREG) &&
1903                     (va->va_mask & AT_SIZE) &&
1904                     (va->va_size == 0))
1905                         disp = NTCREATEX_DISP_OVERWRITE_IF;
1906                 else
1907                         disp = NTCREATEX_DISP_OPEN_IF;
1908         }
1909         xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
1910         error = smbfs_smb_create(dnp,
1911             name, nmlen, xattr,
1912             disp, &scred, &fid);
1913         if (error)
1914                 goto out;
1915 
1916         /*
1917          * XXX: Missing some code here to deal with
1918          * the case where we opened an existing file,
1919          * it's size is larger than 32-bits, and we're
1920          * setting the size from a process that's not
1921          * aware of large file offsets.  i.e.
1922          * from the NFS3 code:
1923          */
1924 #if NOT_YET /* XXX */
1925         if ((vattr.va_mask & AT_SIZE) &&
1926             vp->v_type == VREG) {
1927                 np = VTOSMB(vp);
1928                 /*
1929                  * Check here for large file handled
1930                  * by LF-unaware process (as
1931                  * ufs_create() does)
1932                  */
1933                 if (!(lfaware & FOFFMAX)) {
1934                         mutex_enter(&np->r_statelock);
1935                         if (np->r_size > MAXOFF32_T)
1936                                 error = EOVERFLOW;
1937                         mutex_exit(&np->r_statelock);
1938                 }
1939                 if (!error) {
1940                         vattr.va_mask = AT_SIZE;
1941                         error = smbfssetattr(vp,
1942                             &vattr, 0, cr);
1943                 }
1944         }
1945 #endif /* XXX */
1946         /*
1947          * Should use the fid to get/set the size
1948          * while we have it opened here.  See above.
1949          */
1950 
1951         cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
1952         if (cerror)
1953                 SMBVDEBUG("error %d closing %s\\%s\n",
1954                     cerror, dnp->n_rpath, name);
1955 
1956         /*
1957          * In the open case, the name may differ a little
1958          * from what we passed to create (case, etc.)
1959          * so call lookup to get the (opened) name.
1960          *
1961          * XXX: Could avoid this extra lookup if the
1962          * "createact" result from NT_CREATE says we
1963          * created the object.
1964          */
1965         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
1966         if (error)
1967                 goto out;
1968 
1969         /* update attr and directory cache */
1970         smbfs_attr_touchdir(dnp);
1971 
1972         error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
1973         if (error)
1974                 goto out;
1975 
1976         /* XXX invalidate pages if we truncated? */
1977 
1978         /* Success! */
1979         *vpp = vp;
1980         error = 0;
1981 
1982 out:
1983         smb_credrele(&scred);
1984         smbfs_rw_exit(&dnp->r_rwlock);
1985         if (name != nm)
1986                 smbfs_name_free(name, nmlen);
1987         return (error);
1988 }
1989 
1990 /*
1991  * XXX
1992  * This op should support the new FIGNORECASE flag for case-insensitive
1993  * lookups, per PSARC 2007/244.
1994  */
1995 /* ARGSUSED */
1996 static int
1997 smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
1998         int flags)
1999 {
2000         int             error;
2001         vnode_t         *vp;
2002         smbnode_t       *np;
2003         smbnode_t       *dnp;
2004         struct smb_cred scred;
2005         /* enum smbfsstat status; */
2006         smbmntinfo_t    *smi;
2007 
2008         smi = VTOSMI(dvp);
2009 
2010         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2011                 return (EPERM);
2012 
2013         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2014                 return (EIO);
2015 
2016         dnp = VTOSMB(dvp);
2017         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2018                 return (EINTR);
2019         smb_credinit(&scred, cr);
2020 
2021         /*
2022          * Verify access to the dirctory.
2023          */
2024         error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
2025         if (error)
2026                 goto out;
2027 
2028         /*
2029          * NOTE:  the darwin code gets the "vp" passed in so it looks
2030          * like the "vp" has probably been "lookup"ed by the VFS layer.
2031          * It looks like we will need to lookup the vp to check the
2032          * caches and check if the object being deleted is a directory.
2033          */
2034         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2035         if (error)
2036                 goto out;
2037 
2038         /* Never allow link/unlink directories on CIFS. */
2039         if (vp->v_type == VDIR) {
2040                 VN_RELE(vp);
2041                 error = EPERM;
2042                 goto out;
2043         }
2044 
2045         /*
2046          * Now we have the real reference count on the vnode
2047          * Do we have the file open?
2048          */
2049         np = VTOSMB(vp);
2050         mutex_enter(&np->r_statelock);
2051         if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2052                 /*
2053                  * NFS does a rename on remove here.
2054                  * Probably not applicable for SMB.
2055                  * Like Darwin, just return EBUSY.
2056                  *
2057                  * XXX: Todo - Use Trans2rename, and
2058                  * if that fails, ask the server to
2059                  * set the delete-on-close flag.
2060                  */
2061                 mutex_exit(&np->r_statelock);
2062                 error = EBUSY;
2063         } else {
2064                 smbfs_attrcache_rm_locked(np);
2065                 mutex_exit(&np->r_statelock);
2066 
2067                 error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
2068 
2069                 /*
2070                  * If the file should no longer exist, discard
2071                  * any cached attributes under this node.
2072                  */
2073                 switch (error) {
2074                 case 0:
2075                 case ENOENT:
2076                 case ENOTDIR:
2077                         smbfs_attrcache_prune(np);
2078                         break;
2079                 }
2080         }
2081 
2082         VN_RELE(vp);
2083 
2084 out:
2085         smb_credrele(&scred);
2086         smbfs_rw_exit(&dnp->r_rwlock);
2087 
2088         return (error);
2089 }
2090 
2091 
2092 /*
2093  * XXX
2094  * This op should support the new FIGNORECASE flag for case-insensitive
2095  * lookups, per PSARC 2007/244.
2096  */
2097 /* ARGSUSED */
2098 static int
2099 smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2100         caller_context_t *ct, int flags)
2101 {
2102         /* vnode_t              *realvp; */
2103 
2104         if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2105             curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
2106                 return (EPERM);
2107 
2108         if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
2109             VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
2110             odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
2111             ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2112                 return (EIO);
2113 
2114         return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
2115 }
2116 
2117 /*
2118  * smbfsrename does the real work of renaming in SMBFS
2119  */
2120 /* ARGSUSED */
2121 static int
2122 smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
2123         caller_context_t *ct)
2124 {
2125         int             error;
2126         int             nvp_locked = 0;
2127         vnode_t         *nvp = NULL;
2128         vnode_t         *ovp = NULL;
2129         smbnode_t       *onp;
2130         smbnode_t       *nnp;
2131         smbnode_t       *odnp;
2132         smbnode_t       *ndnp;
2133         struct smb_cred scred;
2134         /* enum smbfsstat       status; */
2135 
2136         ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2137 
2138         if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
2139             strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
2140                 return (EINVAL);
2141 
2142         /*
2143          * Check that everything is on the same filesystem.
2144          * vn_rename checks the fsid's, but in case we don't
2145          * fill those in correctly, check here too.
2146          */
2147         if (odvp->v_vfsp != ndvp->v_vfsp)
2148                 return (EXDEV);
2149 
2150         odnp = VTOSMB(odvp);
2151         ndnp = VTOSMB(ndvp);
2152 
2153         /*
2154          * Avoid deadlock here on old vs new directory nodes
2155          * by always taking the locks in order of address.
2156          * The order is arbitrary, but must be consistent.
2157          */
2158         if (odnp < ndnp) {
2159                 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2160                     SMBINTR(odvp)))
2161                         return (EINTR);
2162                 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2163                     SMBINTR(ndvp))) {
2164                         smbfs_rw_exit(&odnp->r_rwlock);
2165                         return (EINTR);
2166                 }
2167         } else {
2168                 if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
2169                     SMBINTR(ndvp)))
2170                         return (EINTR);
2171                 if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
2172                     SMBINTR(odvp))) {
2173                         smbfs_rw_exit(&ndnp->r_rwlock);
2174                         return (EINTR);
2175                 }
2176         }
2177         smb_credinit(&scred, cr);
2178         /*
2179          * No returns after this point (goto out)
2180          */
2181 
2182         /*
2183          * Need write access on source and target.
2184          * Server takes care of most checks.
2185          */
2186         error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2187         if (error)
2188                 goto out;
2189         if (odvp != ndvp) {
2190                 error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2191                 if (error)
2192                         goto out;
2193         }
2194 
2195         /*
2196          * Lookup the source name.  Must already exist.
2197          */
2198         error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2199         if (error)
2200                 goto out;
2201 
2202         /*
2203          * Lookup the target file.  If it exists, it needs to be
2204          * checked to see whether it is a mount point and whether
2205          * it is active (open).
2206          */
2207         error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
2208         if (!error) {
2209                 /*
2210                  * Target (nvp) already exists.  Check that it
2211                  * has the same type as the source.  The server
2212                  * will check this also, (and more reliably) but
2213                  * this lets us return the correct error codes.
2214                  */
2215                 if (ovp->v_type == VDIR) {
2216                         if (nvp->v_type != VDIR) {
2217                                 error = ENOTDIR;
2218                                 goto out;
2219                         }
2220                 } else {
2221                         if (nvp->v_type == VDIR) {
2222                                 error = EISDIR;
2223                                 goto out;
2224                         }
2225                 }
2226 
2227                 /*
2228                  * POSIX dictates that when the source and target
2229                  * entries refer to the same file object, rename
2230                  * must do nothing and exit without error.
2231                  */
2232                 if (ovp == nvp) {
2233                         error = 0;
2234                         goto out;
2235                 }
2236 
2237                 /*
2238                  * Also must ensure the target is not a mount point,
2239                  * and keep mount/umount away until we're done.
2240                  */
2241                 if (vn_vfsrlock(nvp)) {
2242                         error = EBUSY;
2243                         goto out;
2244                 }
2245                 nvp_locked = 1;
2246                 if (vn_mountedvfs(nvp) != NULL) {
2247                         error = EBUSY;
2248                         goto out;
2249                 }
2250 
2251                 /*
2252                  * CIFS gives a SHARING_VIOLATION error when
2253                  * trying to rename onto an exising object,
2254                  * so try to remove the target first.
2255                  * (Only for files, not directories.)
2256                  */
2257                 if (nvp->v_type == VDIR) {
2258                         error = EEXIST;
2259                         goto out;
2260                 }
2261 
2262                 /*
2263                  * Nodes that are "not active" here have v_count=2
2264                  * because vn_renameat (our caller) did a lookup on
2265                  * both the source and target before this call.
2266                  * Otherwise this similar to smbfs_remove.
2267                  */
2268                 nnp = VTOSMB(nvp);
2269                 mutex_enter(&nnp->r_statelock);
2270                 if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) {
2271                         /*
2272                          * The target file exists, is not the same as
2273                          * the source file, and is active.  Other FS
2274                          * implementations unlink the target here.
2275                          * For SMB, we don't assume we can remove an
2276                          * open file.  Return an error instead.
2277                          */
2278                         mutex_exit(&nnp->r_statelock);
2279                         error = EBUSY;
2280                         goto out;
2281                 }
2282 
2283                 /*
2284                  * Target file is not active. Try to remove it.
2285                  */
2286                 smbfs_attrcache_rm_locked(nnp);
2287                 mutex_exit(&nnp->r_statelock);
2288 
2289                 error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0);
2290 
2291                 /*
2292                  * Similar to smbfs_remove
2293                  */
2294                 switch (error) {
2295                 case 0:
2296                 case ENOENT:
2297                 case ENOTDIR:
2298                         smbfs_attrcache_prune(nnp);
2299                         break;
2300                 }
2301 
2302                 if (error)
2303                         goto out;
2304                 /*
2305                  * OK, removed the target file.  Continue as if
2306                  * lookup target had failed (nvp == NULL).
2307                  */
2308                 vn_vfsunlock(nvp);
2309                 nvp_locked = 0;
2310                 VN_RELE(nvp);
2311                 nvp = NULL;
2312         } /* nvp */
2313 
2314         onp = VTOSMB(ovp);
2315         smbfs_attrcache_remove(onp);
2316 
2317         error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
2318 
2319         /*
2320          * If the old name should no longer exist,
2321          * discard any cached attributes under it.
2322          */
2323         if (error == 0)
2324                 smbfs_attrcache_prune(onp);
2325 
2326 out:
2327         if (nvp) {
2328                 if (nvp_locked)
2329                         vn_vfsunlock(nvp);
2330                 VN_RELE(nvp);
2331         }
2332         if (ovp)
2333                 VN_RELE(ovp);
2334 
2335         smb_credrele(&scred);
2336         smbfs_rw_exit(&odnp->r_rwlock);
2337         smbfs_rw_exit(&ndnp->r_rwlock);
2338 
2339         return (error);
2340 }
2341 
2342 /*
2343  * XXX
2344  * vsecattr_t is new to build 77, and we need to eventually support
2345  * it in order to create an ACL when an object is created.
2346  *
2347  * This op should support the new FIGNORECASE flag for case-insensitive
2348  * lookups, per PSARC 2007/244.
2349  */
2350 /* ARGSUSED */
2351 static int
2352 smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
2353         cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
2354 {
2355         vnode_t         *vp;
2356         struct smbnode  *dnp = VTOSMB(dvp);
2357         struct smbmntinfo *smi = VTOSMI(dvp);
2358         struct smb_cred scred;
2359         struct smbfattr fattr;
2360         const char              *name = (const char *) nm;
2361         int             nmlen = strlen(name);
2362         int             error, hiderr;
2363 
2364         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2365                 return (EPERM);
2366 
2367         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2368                 return (EIO);
2369 
2370         if ((nmlen == 1 && name[0] == '.') ||
2371             (nmlen == 2 && name[0] == '.' && name[1] == '.'))
2372                 return (EEXIST);
2373 
2374         /* Only plain files are allowed in V_XATTRDIR. */
2375         if (dvp->v_flag & V_XATTRDIR)
2376                 return (EINVAL);
2377 
2378         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2379                 return (EINTR);
2380         smb_credinit(&scred, cr);
2381 
2382         /*
2383          * XXX: Do we need r_lkserlock too?
2384          * No use of any shared fid or fctx...
2385          */
2386 
2387         /*
2388          * Require write access in the containing directory.
2389          */
2390         error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2391         if (error)
2392                 goto out;
2393 
2394         error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2395         if (error)
2396                 goto out;
2397 
2398         error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2399         if (error)
2400                 goto out;
2401 
2402         smbfs_attr_touchdir(dnp);
2403 
2404         error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2405         if (error)
2406                 goto out;
2407 
2408         if (name[0] == '.')
2409                 if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2410                         SMBVDEBUG("hide failure %d\n", hiderr);
2411 
2412         /* Success! */
2413         *vpp = vp;
2414         error = 0;
2415 out:
2416         smb_credrele(&scred);
2417         smbfs_rw_exit(&dnp->r_rwlock);
2418 
2419         if (name != nm)
2420                 smbfs_name_free(name, nmlen);
2421 
2422         return (error);
2423 }
2424 
2425 /*
2426  * XXX
2427  * This op should support the new FIGNORECASE flag for case-insensitive
2428  * lookups, per PSARC 2007/244.
2429  */
2430 /* ARGSUSED */
2431 static int
2432 smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2433         caller_context_t *ct, int flags)
2434 {
2435         vnode_t         *vp = NULL;
2436         int             vp_locked = 0;
2437         struct smbmntinfo *smi = VTOSMI(dvp);
2438         struct smbnode  *dnp = VTOSMB(dvp);
2439         struct smbnode  *np;
2440         struct smb_cred scred;
2441         int             error;
2442 
2443         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2444                 return (EPERM);
2445 
2446         if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2447                 return (EIO);
2448 
2449         if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2450                 return (EINTR);
2451         smb_credinit(&scred, cr);
2452 
2453         /*
2454          * Require w/x access in the containing directory.
2455          * Server handles all other access checks.
2456          */
2457         error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2458         if (error)
2459                 goto out;
2460 
2461         /*
2462          * First lookup the entry to be removed.
2463          */
2464         error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2465         if (error)
2466                 goto out;
2467         np = VTOSMB(vp);
2468 
2469         /*
2470          * Disallow rmdir of "." or current dir, or the FS root.
2471          * Also make sure it's a directory, not a mount point,
2472          * and lock to keep mount/umount away until we're done.
2473          */
2474         if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2475                 error = EINVAL;
2476                 goto out;
2477         }
2478         if (vp->v_type != VDIR) {
2479                 error = ENOTDIR;
2480                 goto out;
2481         }
2482         if (vn_vfsrlock(vp)) {
2483                 error = EBUSY;
2484                 goto out;
2485         }
2486         vp_locked = 1;
2487         if (vn_mountedvfs(vp) != NULL) {
2488                 error = EBUSY;
2489                 goto out;
2490         }
2491 
2492         smbfs_attrcache_remove(np);
2493         error = smbfs_smb_rmdir(np, &scred);
2494 
2495         /*
2496          * Similar to smbfs_remove
2497          */
2498         switch (error) {
2499         case 0:
2500         case ENOENT:
2501         case ENOTDIR:
2502                 smbfs_attrcache_prune(np);
2503                 break;
2504         }
2505 
2506         if (error)
2507                 goto out;
2508 
2509         mutex_enter(&np->r_statelock);
2510         dnp->n_flag |= NMODIFIED;
2511         mutex_exit(&np->r_statelock);
2512         smbfs_attr_touchdir(dnp);
2513         smbfs_rmhash(np);
2514 
2515 out:
2516         if (vp) {
2517                 if (vp_locked)
2518                         vn_vfsunlock(vp);
2519                 VN_RELE(vp);
2520         }
2521         smb_credrele(&scred);
2522         smbfs_rw_exit(&dnp->r_rwlock);
2523 
2524         return (error);
2525 }
2526 
2527 
2528 /* ARGSUSED */
2529 static int
2530 smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2531         caller_context_t *ct, int flags)
2532 {
2533         struct smbnode  *np = VTOSMB(vp);
2534         int             error = 0;
2535         smbmntinfo_t    *smi;
2536 
2537         smi = VTOSMI(vp);
2538 
2539         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2540                 return (EIO);
2541 
2542         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2543                 return (EIO);
2544 
2545         /*
2546          * Require read access in the directory.
2547          */
2548         error = smbfs_access(vp, VREAD, 0, cr, ct);
2549         if (error)
2550                 return (error);
2551 
2552         ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2553 
2554         /*
2555          * XXX: Todo readdir cache here
2556          * Note: NFS code is just below this.
2557          *
2558          * I am serializing the entire readdir opreation
2559          * now since we have not yet implemented readdir
2560          * cache. This fix needs to be revisited once
2561          * we implement readdir cache.
2562          */
2563         if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2564                 return (EINTR);
2565 
2566         error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
2567 
2568         smbfs_rw_exit(&np->r_lkserlock);
2569 
2570         return (error);
2571 }
2572 
2573 /* ARGSUSED */
2574 static int
2575 smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2576         caller_context_t *ct)
2577 {
2578         /*
2579          * Note: "limit" tells the SMB-level FindFirst/FindNext
2580          * functions how many directory entries to request in
2581          * each OtW call.  It needs to be large enough so that
2582          * we don't make lots of tiny OtW requests, but there's
2583          * no point making it larger than the maximum number of
2584          * OtW entries that would fit in a maximum sized trans2
2585          * response (64k / 48).  Beyond that, it's just tuning.
2586          * WinNT used 512, Win2k used 1366.  We use 1000.
2587          */
2588         static const int limit = 1000;
2589         /* Largest possible dirent size. */
2590         static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
2591         struct smb_cred scred;
2592         vnode_t         *newvp;
2593         struct smbnode  *np = VTOSMB(vp);
2594         struct smbfs_fctx *ctx;
2595         struct dirent64 *dp;
2596         ssize_t         save_resid;
2597         offset_t        save_offset; /* 64 bits */
2598         int             offset; /* yes, 32 bits */
2599         int             nmlen, error;
2600         ushort_t        reclen;
2601 
2602         ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
2603 
2604         /* Make sure we serialize for n_dirseq use. */
2605         ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2606 
2607         /*
2608          * Make sure smbfs_open filled in n_dirseq
2609          */
2610         if (np->n_dirseq == NULL)
2611                 return (EBADF);
2612 
2613         /* Check for overflow of (32-bit) directory offset. */
2614         if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
2615             (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
2616                 return (EINVAL);
2617 
2618         /* Require space for at least one dirent. */
2619         if (uio->uio_resid < dbufsiz)
2620                 return (EINVAL);
2621 
2622         SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2623         smb_credinit(&scred, cr);
2624         dp = kmem_alloc(dbufsiz, KM_SLEEP);
2625 
2626         save_resid = uio->uio_resid;
2627         save_offset = uio->uio_loffset;
2628         offset = uio->uio_offset;
2629         SMBVDEBUG("in: offset=%d, resid=%d\n",
2630             (int)uio->uio_offset, (int)uio->uio_resid);
2631         error = 0;
2632 
2633         /*
2634          * Generate the "." and ".." entries here so we can
2635          * (1) make sure they appear (but only once), and
2636          * (2) deal with getting their I numbers which the
2637          * findnext below does only for normal names.
2638          */
2639         while (offset < FIRST_DIROFS) {
2640                 /*
2641                  * Tricky bit filling in the first two:
2642                  * offset 0 is ".", offset 1 is ".."
2643                  * so strlen of these is offset+1.
2644                  */
2645                 reclen = DIRENT64_RECLEN(offset + 1);
2646                 if (uio->uio_resid < reclen)
2647                         goto out;
2648                 bzero(dp, reclen);
2649                 dp->d_reclen = reclen;
2650                 dp->d_name[0] = '.';
2651                 dp->d_name[1] = '.';
2652                 dp->d_name[offset + 1] = '\0';
2653                 /*
2654                  * Want the real I-numbers for the "." and ".."
2655                  * entries.  For these two names, we know that
2656                  * smbfslookup can get the nodes efficiently.
2657                  */
2658                 error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2659                 if (error) {
2660                         dp->d_ino = np->n_ino + offset; /* fiction */
2661                 } else {
2662                         dp->d_ino = VTOSMB(newvp)->n_ino;
2663                         VN_RELE(newvp);
2664                 }
2665                 /*
2666                  * Note: d_off is the offset that a user-level program
2667                  * should seek to for reading the NEXT directory entry.
2668                  * See libc: readdir, telldir, seekdir
2669                  */
2670                 dp->d_off = offset + 1;
2671                 error = uiomove(dp, reclen, UIO_READ, uio);
2672                 if (error)
2673                         goto out;
2674                 /*
2675                  * Note: uiomove updates uio->uio_offset,
2676                  * but we want it to be our "cookie" value,
2677                  * which just counts dirents ignoring size.
2678                  */
2679                 uio->uio_offset = ++offset;
2680         }
2681 
2682         /*
2683          * If there was a backward seek, we have to reopen.
2684          */
2685         if (offset < np->n_dirofs) {
2686                 SMBVDEBUG("Reopening search %d:%d\n",
2687                     offset, np->n_dirofs);
2688                 error = smbfs_smb_findopen(np, "*", 1,
2689                     SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2690                     &scred, &ctx);
2691                 if (error) {
2692                         SMBVDEBUG("can not open search, error = %d", error);
2693                         goto out;
2694                 }
2695                 /* free the old one */
2696                 (void) smbfs_smb_findclose(np->n_dirseq, &scred);
2697                 /* save the new one */
2698                 np->n_dirseq = ctx;
2699                 np->n_dirofs = FIRST_DIROFS;
2700         } else {
2701                 ctx = np->n_dirseq;
2702         }
2703 
2704         /*
2705          * Skip entries before the requested offset.
2706          */
2707         while (np->n_dirofs < offset) {
2708                 error = smbfs_smb_findnext(ctx, limit, &scred);
2709                 if (error != 0)
2710                         goto out;
2711                 np->n_dirofs++;
2712         }
2713 
2714         /*
2715          * While there's room in the caller's buffer:
2716          *      get a directory entry from SMB,
2717          *      convert to a dirent, copyout.
2718          * We stop when there is no longer room for a
2719          * maximum sized dirent because we must decide
2720          * before we know anything about the next entry.
2721          */
2722         while (uio->uio_resid >= dbufsiz) {
2723                 error = smbfs_smb_findnext(ctx, limit, &scred);
2724                 if (error != 0)
2725                         goto out;
2726                 np->n_dirofs++;
2727 
2728                 /* Sanity check the name length. */
2729                 nmlen = ctx->f_nmlen;
2730                 if (nmlen > SMB_MAXFNAMELEN) {
2731                         nmlen = SMB_MAXFNAMELEN;
2732                         SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2733                 }
2734                 if (smbfs_fastlookup) {
2735                         /* See comment at smbfs_fastlookup above. */
2736                         if (smbfs_nget(vp, ctx->f_name, nmlen,
2737                             &ctx->f_attr, &newvp) == 0)
2738                                 VN_RELE(newvp);
2739                 }
2740 
2741                 reclen = DIRENT64_RECLEN(nmlen);
2742                 bzero(dp, reclen);
2743                 dp->d_reclen = reclen;
2744                 bcopy(ctx->f_name, dp->d_name, nmlen);
2745                 dp->d_name[nmlen] = '\0';
2746                 dp->d_ino = ctx->f_inum;
2747                 dp->d_off = offset + 1;      /* See d_off comment above */
2748                 error = uiomove(dp, reclen, UIO_READ, uio);
2749                 if (error)
2750                         goto out;
2751                 /* See comment re. uio_offset above. */
2752                 uio->uio_offset = ++offset;
2753         }
2754 
2755 out:
2756         /*
2757          * When we come to the end of a directory, the
2758          * SMB-level functions return ENOENT, but the
2759          * caller is not expecting an error return.
2760          *
2761          * Also note that we must delay the call to
2762          * smbfs_smb_findclose(np->n_dirseq, ...)
2763          * until smbfs_close so that all reads at the
2764          * end of the directory will return no data.
2765          */
2766         if (error == ENOENT) {
2767                 error = 0;
2768                 if (eofp)
2769                         *eofp = 1;
2770         }
2771         /*
2772          * If we encountered an error (i.e. "access denied")
2773          * from the FindFirst call, we will have copied out
2774          * the "." and ".." entries leaving offset == 2.
2775          * In that case, restore the original offset/resid
2776          * so the caller gets no data with the error.
2777          */
2778         if (error != 0 && offset == FIRST_DIROFS) {
2779                 uio->uio_loffset = save_offset;
2780                 uio->uio_resid = save_resid;
2781         }
2782         SMBVDEBUG("out: offset=%d, resid=%d\n",
2783             (int)uio->uio_offset, (int)uio->uio_resid);
2784 
2785         kmem_free(dp, dbufsiz);
2786         smb_credrele(&scred);
2787         return (error);
2788 }
2789 
2790 
2791 /*
2792  * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2793  * are optional functions that are called by:
2794  *    getdents, before/after VOP_READDIR
2795  *    pread, before/after ... VOP_READ
2796  *    pwrite, before/after ... VOP_WRITE
2797  *    (other places)
2798  *
2799  * Careful here: None of the above check for any
2800  * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
2801  * In fact, the return value from _rwlock is NOT
2802  * an error code, but V_WRITELOCK_TRUE / _FALSE.
2803  *
2804  * Therefore, it's up to _this_ code to make sure
2805  * the lock state remains balanced, which means
2806  * we can't "bail out" on interrupts, etc.
2807  */
2808 
2809 /* ARGSUSED2 */
2810 static int
2811 smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2812 {
2813         smbnode_t       *np = VTOSMB(vp);
2814 
2815         if (!write_lock) {
2816                 (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2817                 return (V_WRITELOCK_FALSE);
2818         }
2819 
2820 
2821         (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2822         return (V_WRITELOCK_TRUE);
2823 }
2824 
2825 /* ARGSUSED */
2826 static void
2827 smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2828 {
2829         smbnode_t       *np = VTOSMB(vp);
2830 
2831         smbfs_rw_exit(&np->r_rwlock);
2832 }
2833 
2834 
2835 /* ARGSUSED */
2836 static int
2837 smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2838 {
2839         smbmntinfo_t    *smi;
2840 
2841         smi = VTOSMI(vp);
2842 
2843         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2844                 return (EPERM);
2845 
2846         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2847                 return (EIO);
2848 
2849         /*
2850          * Because we stuff the readdir cookie into the offset field
2851          * someone may attempt to do an lseek with the cookie which
2852          * we want to succeed.
2853          */
2854         if (vp->v_type == VDIR)
2855                 return (0);
2856 
2857         /* Like NFS3, just check for 63-bit overflow. */
2858         if (*noffp < 0)
2859                 return (EINVAL);
2860 
2861         return (0);
2862 }
2863 
2864 
2865 /*
2866  * XXX
2867  * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2868  */
2869 static int
2870 smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2871         offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2872         caller_context_t *ct)
2873 {
2874         if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
2875                 return (EIO);
2876 
2877         if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2878                 return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2879         else
2880                 return (ENOSYS);
2881 }
2882 
2883 /*
2884  * Free storage space associated with the specified vnode.  The portion
2885  * to be freed is specified by bfp->l_start and bfp->l_len (already
2886  * normalized to a "whence" of 0).
2887  *
2888  * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2889  */
2890 /* ARGSUSED */
2891 static int
2892 smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2893         offset_t offset, cred_t *cr, caller_context_t *ct)
2894 {
2895         int             error;
2896         smbmntinfo_t    *smi;
2897 
2898         smi = VTOSMI(vp);
2899 
2900         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2901                 return (EIO);
2902 
2903         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2904                 return (EIO);
2905 
2906         /* Caller (fcntl) has checked v_type */
2907         ASSERT(vp->v_type == VREG);
2908         if (cmd != F_FREESP)
2909                 return (EINVAL);
2910 
2911         /*
2912          * Like NFS3, no 32-bit offset checks here.
2913          * Our SMB layer takes care to return EFBIG
2914          * when it has to fallback to a 32-bit call.
2915          */
2916 
2917         error = convoff(vp, bfp, 0, offset);
2918         if (!error) {
2919                 ASSERT(bfp->l_start >= 0);
2920                 if (bfp->l_len == 0) {
2921                         struct vattr va;
2922 
2923                         /*
2924                          * ftruncate should not change the ctime and
2925                          * mtime if we truncate the file to its
2926                          * previous size.
2927                          */
2928                         va.va_mask = AT_SIZE;
2929                         error = smbfsgetattr(vp, &va, cr);
2930                         if (error || va.va_size == bfp->l_start)
2931                                 return (error);
2932                         va.va_mask = AT_SIZE;
2933                         va.va_size = bfp->l_start;
2934                         error = smbfssetattr(vp, &va, 0, cr);
2935                 } else
2936                         error = EINVAL;
2937         }
2938 
2939         return (error);
2940 }
2941 
2942 /* ARGSUSED */
2943 static int
2944 smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
2945         caller_context_t *ct)
2946 {
2947         vfs_t *vfs;
2948         smbmntinfo_t *smi;
2949         struct smb_share *ssp;
2950 
2951         vfs = vp->v_vfsp;
2952         smi = VFTOSMI(vfs);
2953 
2954         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2955                 return (EIO);
2956 
2957         if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2958                 return (EIO);
2959 
2960         switch (cmd) {
2961         case _PC_FILESIZEBITS:
2962                 ssp = smi->smi_share;
2963                 if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
2964                         *valp = 64;
2965                 else
2966                         *valp = 32;
2967                 break;
2968 
2969         case _PC_LINK_MAX:
2970                 /* We only ever report one link to an object */
2971                 *valp = 1;
2972                 break;
2973 
2974         case _PC_ACL_ENABLED:
2975                 /*
2976                  * Always indicate that ACLs are enabled and
2977                  * that we support ACE_T format, otherwise
2978                  * libsec will ask for ACLENT_T format data
2979                  * which we don't support.
2980                  */
2981                 *valp = _ACL_ACE_ENABLED;
2982                 break;
2983 
2984         case _PC_SYMLINK_MAX:   /* No symlinks until we do Unix extensions */
2985                 *valp = 0;
2986                 break;
2987 
2988         case _PC_XATTR_EXISTS:
2989                 if (vfs->vfs_flag & VFS_XATTR) {
2990                         *valp = smbfs_xa_exists(vp, cr);
2991                         break;
2992                 }
2993                 return (EINVAL);
2994 
2995         case _PC_TIMESTAMP_RESOLUTION:
2996                 /*
2997                  * Windows times are tenths of microseconds
2998                  * (multiples of 100 nanoseconds).
2999                  */
3000                 *valp = 100L;
3001                 break;
3002 
3003         default:
3004                 return (fs_pathconf(vp, cmd, valp, cr, ct));
3005         }
3006         return (0);
3007 }
3008 
3009 /* ARGSUSED */
3010 static int
3011 smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3012         caller_context_t *ct)
3013 {
3014         vfs_t *vfsp;
3015         smbmntinfo_t *smi;
3016         int     error;
3017         uint_t  mask;
3018 
3019         vfsp = vp->v_vfsp;
3020         smi = VFTOSMI(vfsp);
3021 
3022         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3023                 return (EIO);
3024 
3025         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3026                 return (EIO);
3027 
3028         /*
3029          * Our _pathconf indicates _ACL_ACE_ENABLED,
3030          * so we should only see VSA_ACE, etc here.
3031          * Note: vn_create asks for VSA_DFACLCNT,
3032          * and it expects ENOSYS and empty data.
3033          */
3034         mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
3035             VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
3036         if (mask == 0)
3037                 return (ENOSYS);
3038 
3039         if (smi->smi_flags & SMI_ACL)
3040                 error = smbfs_acl_getvsa(vp, vsa, flag, cr);
3041         else
3042                 error = ENOSYS;
3043 
3044         if (error == ENOSYS)
3045                 error = fs_fab_acl(vp, vsa, flag, cr, ct);
3046 
3047         return (error);
3048 }
3049 
3050 /* ARGSUSED */
3051 static int
3052 smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
3053         caller_context_t *ct)
3054 {
3055         vfs_t *vfsp;
3056         smbmntinfo_t *smi;
3057         int     error;
3058         uint_t  mask;
3059 
3060         vfsp = vp->v_vfsp;
3061         smi = VFTOSMI(vfsp);
3062 
3063         if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
3064                 return (EIO);
3065 
3066         if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
3067                 return (EIO);
3068 
3069         /*
3070          * Our _pathconf indicates _ACL_ACE_ENABLED,
3071          * so we should only see VSA_ACE, etc here.
3072          */
3073         mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
3074         if (mask == 0)
3075                 return (ENOSYS);
3076 
3077         if (vfsp->vfs_flag & VFS_RDONLY)
3078                 return (EROFS);
3079 
3080         /*
3081          * Allow only the mount owner to do this.
3082          * See comments at smbfs_access_rwx.
3083          */
3084         error = secpolicy_vnode_setdac(cr, smi->smi_uid);
3085         if (error != 0)
3086                 return (error);
3087 
3088         if (smi->smi_flags & SMI_ACL)
3089                 error = smbfs_acl_setvsa(vp, vsa, flag, cr);
3090         else
3091                 error = ENOSYS;
3092 
3093         return (error);
3094 }
3095 
3096 
3097 /*
3098  * XXX
3099  * This op should eventually support PSARC 2007/268.
3100  */
3101 static int
3102 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
3103         caller_context_t *ct)
3104 {
3105         if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
3106                 return (EIO);
3107 
3108         if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
3109                 return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
3110         else
3111                 return (ENOSYS);
3112 }