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
smbfs_hash(uint32_t ival,const char * name,int nmlen)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
smbfs_gethash(const char * rpath,int rplen)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
smbfs_getino(struct smbnode * dnp,const char * name,int nmlen)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 *
smbfs_name_alloc(const char * name,int nmlen)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
smbfs_name_free(const char * name,int nmlen)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
smbfs_nget(vnode_t * dvp,const char * name,int nmlen,struct smbfattr * fap,vnode_t ** vpp)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
smbfs_attr_touchdir(struct smbnode * dnp)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
smbfs_attrcache_remove(struct smbnode * np)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
smbfs_attrcache_rm_locked(struct smbnode * np)244 smbfs_attrcache_rm_locked(struct smbnode *np)
245 {
246 	ASSERT(MUTEX_HELD(&np->r_statelock));
247 	np->r_attrtime = gethrtime();
248 }
249