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
80static inline uint32_t
81smbfs_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 */
96uint32_t
97smbfs_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 */
109uint32_t
110smbfs_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 */
133char *
134smbfs_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 */
149void
150smbfs_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 */
160int
161smbfs_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 */
211void
212smbfs_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
232void
233smbfs_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
243void
244smbfs_attrcache_rm_locked(struct smbnode *np)
245{
246	ASSERT(MUTEX_HELD(&np->r_statelock));
247	np->r_attrtime = gethrtime();
248}
249