1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*d2488fe8SGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #include <sys/types.h>
272c2961f8Sjose borrego #include <sys/param.h>
28da6c28aaSamw #include <sys/sunddi.h>
29da6c28aaSamw #include <sys/errno.h>
30b819cea2SGordon Ross #include <sys/extdirent.h>
31da6c28aaSamw #include <smbsrv/string.h>
32da6c28aaSamw #include <smbsrv/smb_vops.h>
33bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
34da6c28aaSamw #include <smbsrv/smb_fsops.h>
35da6c28aaSamw 
362c2961f8Sjose borrego /*
372c2961f8Sjose borrego  * Characters we don't allow in DOS file names.
382c2961f8Sjose borrego  * If a filename contains any of these chars, it should get mangled.
392c2961f8Sjose borrego  *
402c2961f8Sjose borrego  * '.' is also an invalid DOS char but since it's a special
412c2961f8Sjose borrego  * case it doesn't appear in the list.
422c2961f8Sjose borrego  */
438622ec45SGordon Ross static const char invalid_dos_chars[] =
442c2961f8Sjose borrego 	"\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
452c2961f8Sjose borrego 	"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
462c2961f8Sjose borrego 	" \"/\\:|<>*?";
472c2961f8Sjose borrego 
482c2961f8Sjose borrego /*
492c2961f8Sjose borrego  * According to MSKB article #142982, Windows deletes invalid chars and
502c2961f8Sjose borrego  * spaces from file name in mangling process; and invalid chars include:
512c2961f8Sjose borrego  * ."/\[]:;=,
522c2961f8Sjose borrego  *
532c2961f8Sjose borrego  * But some of these chars and some other chars (e.g. +) are replaced
542c2961f8Sjose borrego  * with underscore (_). They are introduced here as special chars.
552c2961f8Sjose borrego  */
568622ec45SGordon Ross static const char special_chars[] = "[];=,+";
572c2961f8Sjose borrego 
582c2961f8Sjose borrego #define	isinvalid(c)	(strchr(invalid_dos_chars, c) || (c & 0x80))
592c2961f8Sjose borrego 
60148c5f43SAlan Wright static int smb_generate_mangle(uint64_t, char *, size_t);
61148c5f43SAlan Wright static char smb_mangle_char(char);
62da6c28aaSamw 
63da6c28aaSamw /*
642c2961f8Sjose borrego  * Return true if name contains characters that are invalid in a file
652c2961f8Sjose borrego  * name or it is a reserved DOS device name.  Otherwise, returns false.
66da6c28aaSamw  *
672c2961f8Sjose borrego  * Control characters (values 0 - 31) and the following characters are
682c2961f8Sjose borrego  * invalid:
692c2961f8Sjose borrego  *	< > : " / \ | ? *
70da6c28aaSamw  */
712c2961f8Sjose borrego boolean_t
smb_is_invalid_filename(const char * name)722c2961f8Sjose borrego smb_is_invalid_filename(const char *name)
73da6c28aaSamw {
742c2961f8Sjose borrego 	const char *p;
75da6c28aaSamw 
762c2961f8Sjose borrego 	if ((p = strpbrk(name, invalid_dos_chars)) != NULL) {
772c2961f8Sjose borrego 		if (*p != ' ')
782c2961f8Sjose borrego 			return (B_TRUE);
792c2961f8Sjose borrego 	}
802c2961f8Sjose borrego 
812c2961f8Sjose borrego 	return (smb_is_reserved_dos_name(name));
82da6c28aaSamw }
83da6c28aaSamw 
84da6c28aaSamw /*
85da6c28aaSamw  * smb_is_reserved_dos_name
86da6c28aaSamw  *
872c2961f8Sjose borrego  * This function checks if the name is a reserved DOS device name.
882c2961f8Sjose borrego  * The device name should not be followed immediately by an extension,
892c2961f8Sjose borrego  * for example, NUL.txt.
90da6c28aaSamw  */
91cb174861Sjoyce mcintosh boolean_t
smb_is_reserved_dos_name(const char * name)922c2961f8Sjose borrego smb_is_reserved_dos_name(const char *name)
93da6c28aaSamw {
942c2961f8Sjose borrego 	static char *cnames[] = { "CLOCK$", "COM1", "COM2", "COM3", "COM4",
952c2961f8Sjose borrego 		"COM5", "COM6", "COM7", "COM8", "COM9", "CON" };
962c2961f8Sjose borrego 	static char *lnames[] = { "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
972c2961f8Sjose borrego 		"LPT6", "LPT7", "LPT8", "LPT9" };
982c2961f8Sjose borrego 	static char *others[] = { "AUX", "NUL", "PRN" };
992c2961f8Sjose borrego 	char	**reserved;
100da6c28aaSamw 	char	ch;
1012c2961f8Sjose borrego 	int	n_reserved;
1022c2961f8Sjose borrego 	int	len;
1032c2961f8Sjose borrego 	int	i;
104da6c28aaSamw 
105bbf6f00cSJordan Brown 	ch = smb_toupper(*name);
106da6c28aaSamw 
107da6c28aaSamw 	switch (ch) {
108da6c28aaSamw 	case 'A':
1092c2961f8Sjose borrego 	case 'N':
1102c2961f8Sjose borrego 	case 'P':
1112c2961f8Sjose borrego 		reserved = others;
1122c2961f8Sjose borrego 		n_reserved = sizeof (others) / sizeof (others[0]);
113da6c28aaSamw 		break;
114da6c28aaSamw 	case 'C':
1152c2961f8Sjose borrego 		reserved = cnames;
1162c2961f8Sjose borrego 		n_reserved = sizeof (cnames) / sizeof (cnames[0]);
117da6c28aaSamw 		break;
118da6c28aaSamw 	case 'L':
1192c2961f8Sjose borrego 		reserved = lnames;
1202c2961f8Sjose borrego 		n_reserved = sizeof (lnames) / sizeof (lnames[0]);
121da6c28aaSamw 		break;
1222c2961f8Sjose borrego 	default:
1232c2961f8Sjose borrego 		return (B_FALSE);
124da6c28aaSamw 	}
125da6c28aaSamw 
1262c2961f8Sjose borrego 	for (i  = 0; i < n_reserved; ++i) {
1272c2961f8Sjose borrego 		len = strlen(reserved[i]);
1282c2961f8Sjose borrego 
129bbf6f00cSJordan Brown 		if (smb_strcasecmp(reserved[i], name, len) == 0) {
1302c2961f8Sjose borrego 			ch = *(name + len);
1312c2961f8Sjose borrego 			if ((ch == '\0') || (ch == '.'))
1322c2961f8Sjose borrego 				return (B_TRUE);
133da6c28aaSamw 		}
134da6c28aaSamw 	}
135da6c28aaSamw 
1362c2961f8Sjose borrego 	return (B_FALSE);
137da6c28aaSamw }
138da6c28aaSamw 
139da6c28aaSamw /*
140148c5f43SAlan Wright  * smb_needs_mangled
141148c5f43SAlan Wright  *
142148c5f43SAlan Wright  * A name needs to be mangled if any of the following are true:
143148c5f43SAlan Wright  * - the first character is dot (.) and the name is not "." or ".."
144148c5f43SAlan Wright  * - the name contains illegal or special charsacter
145148c5f43SAlan Wright  * - the name name length > 12
146148c5f43SAlan Wright  * - the number of dots == 0 and length > 8
147148c5f43SAlan Wright  * - the number of dots > 1
148148c5f43SAlan Wright  * - the number of dots == 1 and name is not 8.3
149da6c28aaSamw  */
150148c5f43SAlan Wright boolean_t
smb_needs_mangled(const char * name)151148c5f43SAlan Wright smb_needs_mangled(const char *name)
152da6c28aaSamw {
153148c5f43SAlan Wright 	int len, extlen, ndots;
154148c5f43SAlan Wright 	const char *p;
155148c5f43SAlan Wright 	const char *last_dot;
156da6c28aaSamw 
157da6c28aaSamw 	if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
158148c5f43SAlan Wright 		return (B_FALSE);
159da6c28aaSamw 
160da6c28aaSamw 	if (*name == '.')
161148c5f43SAlan Wright 		return (B_TRUE);
162148c5f43SAlan Wright 
163148c5f43SAlan Wright 	len = 0;
164148c5f43SAlan Wright 	ndots = 0;
165148c5f43SAlan Wright 	last_dot = NULL;
166148c5f43SAlan Wright 	for (p = name; *p != '\0'; ++p) {
167148c5f43SAlan Wright 		if (smb_iscntrl(*p) ||
168148c5f43SAlan Wright 		    (strchr(special_chars, *p) != NULL) ||
169148c5f43SAlan Wright 		    (strchr(invalid_dos_chars, *p)) != NULL)
170148c5f43SAlan Wright 			return (B_TRUE);
171da6c28aaSamw 
172148c5f43SAlan Wright 		if (*p == '.') {
173148c5f43SAlan Wright 			++ndots;
174148c5f43SAlan Wright 			last_dot = p;
175148c5f43SAlan Wright 		}
176148c5f43SAlan Wright 		++len;
177da6c28aaSamw 	}
178da6c28aaSamw 
179148c5f43SAlan Wright 	if ((len > SMB_NAME83_LEN) ||
180148c5f43SAlan Wright 	    (ndots == 0 && len > SMB_NAME83_BASELEN) ||
181148c5f43SAlan Wright 	    (ndots > 1)) {
182148c5f43SAlan Wright 		return (B_TRUE);
183da6c28aaSamw 	}
184da6c28aaSamw 
185148c5f43SAlan Wright 	if (last_dot != NULL) {
186148c5f43SAlan Wright 		extlen = strlen(last_dot + 1);
187148c5f43SAlan Wright 		if ((extlen == 0) || (extlen > SMB_NAME83_EXTLEN))
188148c5f43SAlan Wright 			return (B_TRUE);
189da6c28aaSamw 
190148c5f43SAlan Wright 		if ((len - extlen - 1) > SMB_NAME83_BASELEN)
191148c5f43SAlan Wright 			return (B_TRUE);
192da6c28aaSamw 	}
193da6c28aaSamw 
194148c5f43SAlan Wright 	return (B_FALSE);
195da6c28aaSamw }
196da6c28aaSamw 
197da6c28aaSamw /*
198da6c28aaSamw  * smb_mangle_char
199da6c28aaSamw  *
200148c5f43SAlan Wright  * If c is an invalid DOS character or non-ascii, it should
201148c5f43SAlan Wright  * not be used in the mangled name. We return -1 to indicate
202148c5f43SAlan Wright  * an invalid character.
203da6c28aaSamw  *
204148c5f43SAlan Wright  * If c is a special chars, it should be replaced with '_'.
205da6c28aaSamw  *
206148c5f43SAlan Wright  * Otherwise c is returned as uppercase.
207da6c28aaSamw  */
208148c5f43SAlan Wright static char
smb_mangle_char(char c)209148c5f43SAlan Wright smb_mangle_char(char c)
210da6c28aaSamw {
211148c5f43SAlan Wright 	if (isinvalid(c))
212148c5f43SAlan Wright 		return (-1);
213da6c28aaSamw 
214148c5f43SAlan Wright 	if (strchr(special_chars, c))
215da6c28aaSamw 		return ('_');
216da6c28aaSamw 
217148c5f43SAlan Wright 	return (smb_toupper(c));
218da6c28aaSamw }
219da6c28aaSamw 
220da6c28aaSamw /*
221da6c28aaSamw  * smb_generate_mangle
222da6c28aaSamw  *
223148c5f43SAlan Wright  * Generate a mangle string containing at least 2 characters and
224148c5f43SAlan Wright  * at most (buflen - 1) characters.
225da6c28aaSamw  *
226da6c28aaSamw  * Returns the number of chars in the generated mangle.
227da6c28aaSamw  */
228da6c28aaSamw static int
smb_generate_mangle(uint64_t fid,char * buf,size_t buflen)229148c5f43SAlan Wright smb_generate_mangle(uint64_t fid, char *buf, size_t buflen)
230da6c28aaSamw {
231da6c28aaSamw 	static char *base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
232148c5f43SAlan Wright 	char *p = buf;
23348557149Sjoyce mcintosh 	int i;
234da6c28aaSamw 
23548557149Sjoyce mcintosh 	if (fid == 0)
23648557149Sjoyce mcintosh 		fid = (uint64_t)-1;
237da6c28aaSamw 
23848557149Sjoyce mcintosh 	*p++ = '~';
23948557149Sjoyce mcintosh 	for (i = 2; (i < buflen) && (fid > 0); fid /= 36, ++i)
24048557149Sjoyce mcintosh 		*p++ = base36[fid % 36];
24148557149Sjoyce mcintosh 	*p = '\0';
24248557149Sjoyce mcintosh 
24348557149Sjoyce mcintosh 	return (i - 1);
244da6c28aaSamw }
245da6c28aaSamw 
246da6c28aaSamw /*
247148c5f43SAlan Wright  * smb_maybe_mangled
248da6c28aaSamw  *
2492c2961f8Sjose borrego  * Mangled names should be valid DOS file names: less than 12 characters
2502c2961f8Sjose borrego  * long, contain at least one tilde character and conform to an 8.3 name
2512c2961f8Sjose borrego  * format.
252da6c28aaSamw  *
2532c2961f8Sjose borrego  * Returns true if the name looks like a mangled name.
254da6c28aaSamw  */
255148c5f43SAlan Wright boolean_t
smb_maybe_mangled(char * name)256148c5f43SAlan Wright smb_maybe_mangled(char *name)
257da6c28aaSamw {
2582c2961f8Sjose borrego 	const char *p;
2592c2961f8Sjose borrego 	boolean_t has_tilde = B_FALSE;
2602c2961f8Sjose borrego 	int ndots = 0;
2612c2961f8Sjose borrego 	int i;
2622c2961f8Sjose borrego 
2632c2961f8Sjose borrego 	for (p = name, i = 0; (*p != '\0') && (i < SMB_NAME83_LEN); i++, p++) {
2642c2961f8Sjose borrego 		if ((strchr(special_chars, *p) != NULL) ||
2652c2961f8Sjose borrego 		    (strchr(invalid_dos_chars, *p) != NULL))
2662c2961f8Sjose borrego 			return (B_FALSE);
2672c2961f8Sjose borrego 
2682c2961f8Sjose borrego 		if (*p == '.') {
2692c2961f8Sjose borrego 			if ((++ndots) > 1)
2702c2961f8Sjose borrego 				return (B_FALSE);
2712c2961f8Sjose borrego 		}
272da6c28aaSamw 
2732c2961f8Sjose borrego 		if ((*p == '~') && (i < SMB_NAME83_BASELEN))
2742c2961f8Sjose borrego 			has_tilde = B_TRUE;
275da6c28aaSamw 
2762c2961f8Sjose borrego 		if (*p == '.' && !has_tilde)
2772c2961f8Sjose borrego 			return (B_FALSE);
278da6c28aaSamw 	}
279da6c28aaSamw 
280148c5f43SAlan Wright 	return ((*p == '\0') && has_tilde);
281da6c28aaSamw }
282da6c28aaSamw 
283da6c28aaSamw /*
284148c5f43SAlan Wright  * smb_mangle
285da6c28aaSamw  *
286da6c28aaSamw  * Microsoft knowledge base article #142982 describes how Windows
287da6c28aaSamw  * generates 8.3 filenames from long file names. Some other details
288da6c28aaSamw  * can be found in article #114816.
289da6c28aaSamw  *
290148c5f43SAlan Wright  * This function will mangle the name whether mangling is required
291148c5f43SAlan Wright  * or not. Callers should use smb_needs_mangled() to determine whether
292148c5f43SAlan Wright  * mangling is required.
293da6c28aaSamw  *
294148c5f43SAlan Wright  * name		original file name
295148c5f43SAlan Wright  * fid		inode number to generate unique mangle
296148c5f43SAlan Wright  * buf		output buffer (buflen bytes) to contain mangled name
297da6c28aaSamw  */
298148c5f43SAlan Wright void
smb_mangle(const char * name,ino64_t fid,char * buf,size_t buflen)299148c5f43SAlan Wright smb_mangle(const char *name, ino64_t fid, char *buf, size_t buflen)
300da6c28aaSamw {
301148c5f43SAlan Wright 	int i, avail;
302148c5f43SAlan Wright 	const char *p;
303148c5f43SAlan Wright 	char c;
304148c5f43SAlan Wright 	char *pbuf;
305148c5f43SAlan Wright 	char mangle_buf[SMB_NAME83_BASELEN];
306da6c28aaSamw 
307148c5f43SAlan Wright 	ASSERT(name && buf && (buflen >= SMB_SHORTNAMELEN));
308da6c28aaSamw 
309148c5f43SAlan Wright 	avail = SMB_NAME83_BASELEN -
310148c5f43SAlan Wright 	    smb_generate_mangle(fid, mangle_buf, SMB_NAME83_BASELEN);
311148c5f43SAlan Wright 	name += strspn(name, ".");
312da6c28aaSamw 
313da6c28aaSamw 	/*
314148c5f43SAlan Wright 	 * Copy up to avail characters from the base part of name
315148c5f43SAlan Wright 	 * to buf then append the generated mangle string.
316da6c28aaSamw 	 */
317148c5f43SAlan Wright 	p = name;
318148c5f43SAlan Wright 	pbuf = buf;
319148c5f43SAlan Wright 	for (i = 0; (i < avail) && (*p != '\0') && (*p != '.'); ++i, ++p) {
320148c5f43SAlan Wright 		if ((c = smb_mangle_char(*p)) == -1)
321da6c28aaSamw 			continue;
322148c5f43SAlan Wright 		*pbuf++ = c;
323da6c28aaSamw 	}
324148c5f43SAlan Wright 	*pbuf = '\0';
325148c5f43SAlan Wright 	(void) strlcat(pbuf, mangle_buf, SMB_NAME83_BASELEN);
326148c5f43SAlan Wright 	pbuf = strchr(pbuf, '\0');
327da6c28aaSamw 
328148c5f43SAlan Wright 	/*
329148c5f43SAlan Wright 	 * Find the last dot in the name. If there is a dot and an
330148c5f43SAlan Wright 	 * extension, append '.' and up to SMB_NAME83_EXTLEN extension
331148c5f43SAlan Wright 	 * characters to the mangled name.
332148c5f43SAlan Wright 	 */
333148c5f43SAlan Wright 	if (((p = strrchr(name, '.')) != NULL) && (*(++p) != '\0')) {
334148c5f43SAlan Wright 		*pbuf++ = '.';
335148c5f43SAlan Wright 		for (i = 0; (i < SMB_NAME83_EXTLEN) && (*p != '\0'); ++i, ++p) {
336148c5f43SAlan Wright 			if ((c = smb_mangle_char(*p)) == -1)
337148c5f43SAlan Wright 				continue;
338148c5f43SAlan Wright 			*pbuf++ = c;
339da6c28aaSamw 		}
340da6c28aaSamw 	}
341da6c28aaSamw 
342148c5f43SAlan Wright 	*pbuf = '\0';
343da6c28aaSamw }
344da6c28aaSamw 
345da6c28aaSamw /*
346148c5f43SAlan Wright  * smb_unmangle
347da6c28aaSamw  *
348da6c28aaSamw  * Given a mangled name, try to find the real file name as it appears
3498b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * in the directory entry.
3508b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *
351148c5f43SAlan Wright  * smb_unmangle should only be called on names for which
352148c5f43SAlan Wright  * smb_maybe_mangled() is true
3538b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *
354*d2488fe8SGordon Ross  * The flags arg is no longer used, but retained just to avoid
355*d2488fe8SGordon Ross  * changing the many callers of this function.
3568b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *
3578b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  * Returns:
3588b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *   0       - SUCCESS. Unmangled name is returned in namebuf.
3598b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *   EINVAL  - a parameter was invalid.
3608b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *   ENOTDIR - dnode is not a directory node.
3618b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States  *   ENOENT  - an unmangled name could not be found.
362da6c28aaSamw  */
3638b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States #define	SMB_UNMANGLE_BUFSIZE	(4 * 1024)
364da6c28aaSamw int
smb_unmangle(smb_node_t * dnode,char * name,char * namebuf,int buflen,uint32_t flags)365148c5f43SAlan Wright smb_unmangle(smb_node_t *dnode, char *name, char *namebuf,
366e3f2c991SKeyur Desai     int buflen, uint32_t flags)
367da6c28aaSamw {
368*d2488fe8SGordon Ross 	_NOTE(ARGUNUSED(flags))	// avoid changing all callers
369*d2488fe8SGordon Ross 	int		err, eof, bufsize;
3708b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	uint64_t	offset;
3718b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	ino64_t		ino;
3728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	char		*namep, *buf;
3738b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	char		shortname[SMB_SHORTNAMELEN];
3748b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	vnode_t		*vp;
375*d2488fe8SGordon Ross 	char		*bufptr;
376*d2488fe8SGordon Ross 	dirent64_t	*dp;
377*d2488fe8SGordon Ross 	cred_t		*cr = zone_kcred();
378*d2488fe8SGordon Ross 	int		rc = ENOENT;
3798b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
3808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (dnode == NULL || name == NULL || namebuf == NULL || buflen == 0)
381da6c28aaSamw 		return (EINVAL);
382da6c28aaSamw 
383148c5f43SAlan Wright 	ASSERT(smb_maybe_mangled(name) == B_TRUE);
384da6c28aaSamw 
3859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (!smb_node_is_dir(dnode))
3868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (ENOTDIR);
387da6c28aaSamw 
3889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	vp = dnode->vp;
3898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	*namebuf = '\0';
390da6c28aaSamw 
3918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	buf = kmem_alloc(SMB_UNMANGLE_BUFSIZE, KM_SLEEP);
392*d2488fe8SGordon Ross 	bufptr = buf;
393*d2488fe8SGordon Ross 	bufsize = 0;
394*d2488fe8SGordon Ross 	offset = 0;	// next entry offset
395*d2488fe8SGordon Ross 	eof = B_FALSE;
396*d2488fe8SGordon Ross 
397*d2488fe8SGordon Ross 	for (;;) {
398*d2488fe8SGordon Ross 		/*
399*d2488fe8SGordon Ross 		 * Read some entries, if buffer empty or
400*d2488fe8SGordon Ross 		 * we've scanned all of it.  Flags zero
401*d2488fe8SGordon Ross 		 * (no edirent, no ABE wanted here)
402*d2488fe8SGordon Ross 		 */
403*d2488fe8SGordon Ross 		if (bufsize <= 0) {
404*d2488fe8SGordon Ross 			bufsize = SMB_UNMANGLE_BUFSIZE;
405*d2488fe8SGordon Ross 			rc = smb_vop_readdir(vp, offset, buf,
406*d2488fe8SGordon Ross 			    &bufsize, &eof, 0, cr);
407*d2488fe8SGordon Ross 			if (rc != 0)
408*d2488fe8SGordon Ross 				break; /* error */
409*d2488fe8SGordon Ross 			if (bufsize == 0) {
410*d2488fe8SGordon Ross 				eof = B_TRUE;
411*d2488fe8SGordon Ross 				rc = ENOENT;
412*d2488fe8SGordon Ross 				break;
4138b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			}
414*d2488fe8SGordon Ross 			bufptr = buf;
415*d2488fe8SGordon Ross 		}
416*d2488fe8SGordon Ross 		/* LINTED pointer alignment */
417*d2488fe8SGordon Ross 		dp = (dirent64_t *)bufptr;
418*d2488fe8SGordon Ross 
419*d2488fe8SGordon Ross 		/*
420*d2488fe8SGordon Ross 		 * Partial records are not supposed to happen,
421*d2488fe8SGordon Ross 		 * but let's be defensive. If this happens,
422*d2488fe8SGordon Ross 		 * restart at the current offset.
423*d2488fe8SGordon Ross 		 */
424*d2488fe8SGordon Ross 		bufptr += dp->d_reclen;
425*d2488fe8SGordon Ross 		bufsize -= dp->d_reclen;
426*d2488fe8SGordon Ross 		if (bufsize < 0)
427*d2488fe8SGordon Ross 			continue;
4288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
429*d2488fe8SGordon Ross 		offset = dp->d_off;
430*d2488fe8SGordon Ross 		ino = dp->d_ino;
431*d2488fe8SGordon Ross 		namep = dp->d_name;
432da6c28aaSamw 
433*d2488fe8SGordon Ross 		/* skip non utf8 filename */
434*d2488fe8SGordon Ross 		if (u8_validate(namep, strlen(namep), NULL,
435*d2488fe8SGordon Ross 		    U8_VALIDATE_ENTIRE, &err) < 0)
436*d2488fe8SGordon Ross 			continue;
4378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
438*d2488fe8SGordon Ross 		smb_mangle(namep, ino, shortname, SMB_SHORTNAMELEN);
439*d2488fe8SGordon Ross 		if (smb_strcasecmp(name, shortname, 0) == 0) {
440*d2488fe8SGordon Ross 			(void) strlcpy(namebuf, namep, buflen);
441*d2488fe8SGordon Ross 			rc = 0;
4428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 			break;
4438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		}
444da6c28aaSamw 	}
445da6c28aaSamw 
4468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	kmem_free(buf, SMB_UNMANGLE_BUFSIZE);
447*d2488fe8SGordon Ross 	return (rc);
448da6c28aaSamw }
449