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_node.c,v 1.54.52.1 2005/05/27 02:35:28 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  37  * Use is subject to license terms.
  38  *
  39  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  40  */
  41 
  42 #include <sys/param.h>
  43 #include <sys/systm.h>
  44 #include <sys/cred.h>
  45 #include <sys/errno.h>
  46 #include <sys/time.h>
  47 #include <sys/vfs.h>
  48 #include <sys/vnode.h>
  49 #include <sys/kmem.h>
  50 #include <sys/stat.h>
  51 #include <sys/atomic.h>
  52 #include <sys/cmn_err.h>
  53 #include <sys/sysmacros.h>
  54 #include <sys/bitmap.h>
  55 
  56 #include <netsmb/smb_osdep.h>
  57 
  58 #include <netsmb/smb.h>
  59 #include <netsmb/smb_conn.h>
  60 #include <netsmb/smb_subr.h>
  61 
  62 #include <smbfs/smbfs.h>
  63 #include <smbfs/smbfs_node.h>
  64 #include <smbfs/smbfs_subr.h>
  65 
  66 /*
  67  * Lack of inode numbers leads us to the problem of generating them.
  68  * Partially this problem can be solved by having a dir/file cache
  69  * with inode numbers generated from the incremented by one counter.
  70  * However this way will require too much kernel memory, gives all
  71  * sorts of locking and consistency problems, not to mentinon counter
  72  * overflows. So, I'm decided to use a hash function to generate
  73  * pseudo random (and [often?] unique) inode numbers.
  74  */
  75 
  76 /* Magic constants for name hashing. */
  77 #define FNV_32_PRIME ((uint32_t)0x01000193UL)
  78 #define FNV1_32_INIT ((uint32_t)33554467UL)
  79 
  80 static inline uint32_t
  81 smbfs_hash(uint32_t ival, const char *name, int nmlen)
  82 {
  83         uint32_t v;
  84 
  85         for (v = ival; nmlen; name++, nmlen--) {
  86                 v *= FNV_32_PRIME;
  87                 v ^= (uint32_t)*name;
  88         }
  89         return (v);
  90 }
  91 
  92 /*
  93  * Compute the hash of the full (remote) path name
  94  * using the three parts supplied separately.
  95  */
  96 uint32_t
  97 smbfs_gethash(const char *rpath, int rplen)
  98 {
  99         uint32_t v;
 100 
 101         v = smbfs_hash(FNV1_32_INIT, rpath, rplen);
 102         return (v);
 103 }
 104 
 105 /*
 106  * Like smbfs_gethash, but optimized a little by
 107  * starting with the directory hash.
 108  */
 109 uint32_t
 110 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
 111 {
 112         uint32_t ino;
 113         char sep;
 114 
 115         /* Start with directory hash */
 116         ino = (uint32_t)dnp->n_ino;
 117 
 118         /* separator (maybe) */
 119         sep = SMBFS_DNP_SEP(dnp);
 120         if (sep)
 121                 ino = smbfs_hash(ino, &sep, 1);
 122 
 123         /* Now hash this component. */
 124         ino = smbfs_hash(ino, name, nmlen);
 125 
 126         return (ino);
 127 }
 128 
 129 /*
 130  * Allocate and copy a string of passed length.
 131  * The passed length does NOT include the null.
 132  */
 133 char *
 134 smbfs_name_alloc(const char *name, int nmlen)
 135 {
 136         char *cp;
 137 
 138         cp = kmem_alloc(nmlen + 1, KM_SLEEP);
 139         bcopy(name, cp, nmlen);
 140         cp[nmlen] = 0;
 141 
 142         return (cp);
 143 }
 144 
 145 /*
 146  * Free string from smbfs_name_alloc().  Again,
 147  * the passed length does NOT include the null.
 148  */
 149 void
 150 smbfs_name_free(const char *name, int nmlen)
 151 {
 152         kmem_free((char *)name, nmlen + 1);
 153 }
 154 
 155 /*
 156  * smbfs_nget()
 157  *
 158  * Find or create a node under some directory node.
 159  */
 160 int
 161 smbfs_nget(vnode_t *dvp, const char *name, int nmlen,
 162         struct smbfattr *fap, vnode_t **vpp)
 163 {
 164         struct smbnode *dnp = VTOSMB(dvp);
 165         struct smbnode *np;
 166         vnode_t *vp;
 167         char sep;
 168 
 169         ASSERT(fap != NULL);
 170         *vpp = NULL;
 171 
 172         /* Don't expect "" or "." or ".." here anymore. */
 173         if (nmlen == 0 || (nmlen == 1 && name[0] == '.') ||
 174             (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
 175                 return (EINVAL);
 176         }
 177         sep = SMBFS_DNP_SEP(dnp);
 178 
 179         /* Find or create the node. */
 180         np = smbfs_node_findcreate(dnp->n_mount,
 181             dnp->n_rpath, dnp->n_rplen,
 182             name, nmlen, sep, fap);
 183 
 184         /*
 185          * We should have np now, because we passed
 186          * fap != NULL to smbfs_node_findcreate.
 187          */
 188         ASSERT(np != NULL);
 189         vp = SMBTOV(np);
 190 
 191         /*
 192          * Files in an XATTR dir are also XATTR.
 193          */
 194         if (dnp->n_flag & N_XATTR) {
 195                 mutex_enter(&np->r_statelock);
 196                 np->n_flag |= N_XATTR;
 197                 mutex_exit(&np->r_statelock);
 198         }
 199 
 200         /* BSD symlink hack removed (smb_symmagic) */
 201 
 202         *vpp = vp;
 203 
 204         return (0);
 205 }
 206 
 207 /*
 208  * Update the local notion of the mtime of some directory.
 209  * See comments re. r_mtime in smbfs_node.h
 210  */
 211 void
 212 smbfs_attr_touchdir(struct smbnode *dnp)
 213 {
 214 
 215         mutex_enter(&dnp->r_statelock);
 216 
 217         /*
 218          * Now that we keep the client's notion of mtime
 219          * separately from the server, this is easy.
 220          */
 221         dnp->r_mtime = gethrtime();
 222 
 223         /*
 224          * Invalidate the cache, so that we go to the wire
 225          * to check that the server doesn't have a better
 226          * timestamp next time we care.
 227          */
 228         smbfs_attrcache_rm_locked(dnp);
 229         mutex_exit(&dnp->r_statelock);
 230 }
 231 
 232 void
 233 smbfs_attrcache_remove(struct smbnode *np)
 234 {
 235         mutex_enter(&np->r_statelock);
 236         /* smbfs_attrcache_rm_locked(np); */
 237         np->r_attrtime = gethrtime();
 238         mutex_exit(&np->r_statelock);
 239 }
 240 
 241 /* See smbfs_node.h */
 242 #undef smbfs_attrcache_rm_locked
 243 void
 244 smbfs_attrcache_rm_locked(struct smbnode *np)
 245 {
 246         ASSERT(MUTEX_HELD(&np->r_statelock));
 247         np->r_attrtime = gethrtime();
 248 }