xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c (revision 12890:16985853e3aa)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
2212508Samw@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw  */
245331Samw 
255331Samw #include <sys/types.h>
268934SJose.Borrego@Sun.COM #include <sys/param.h>
275331Samw #include <sys/sunddi.h>
285331Samw #include <sys/errno.h>
295331Samw #include <smbsrv/string.h>
305331Samw #include <smbsrv/smb_vops.h>
3110966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
325331Samw #include <smbsrv/smb_fsops.h>
335331Samw 
348934SJose.Borrego@Sun.COM /*
358934SJose.Borrego@Sun.COM  * Characters we don't allow in DOS file names.
368934SJose.Borrego@Sun.COM  * If a filename contains any of these chars, it should get mangled.
378934SJose.Borrego@Sun.COM  *
388934SJose.Borrego@Sun.COM  * '.' is also an invalid DOS char but since it's a special
398934SJose.Borrego@Sun.COM  * case it doesn't appear in the list.
408934SJose.Borrego@Sun.COM  */
418934SJose.Borrego@Sun.COM static char *invalid_dos_chars =
428934SJose.Borrego@Sun.COM 	"\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
438934SJose.Borrego@Sun.COM 	"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
448934SJose.Borrego@Sun.COM 	" \"/\\:|<>*?";
458934SJose.Borrego@Sun.COM 
468934SJose.Borrego@Sun.COM /*
478934SJose.Borrego@Sun.COM  * According to MSKB article #142982, Windows deletes invalid chars and
488934SJose.Borrego@Sun.COM  * spaces from file name in mangling process; and invalid chars include:
498934SJose.Borrego@Sun.COM  * ."/\[]:;=,
508934SJose.Borrego@Sun.COM  *
518934SJose.Borrego@Sun.COM  * But some of these chars and some other chars (e.g. +) are replaced
528934SJose.Borrego@Sun.COM  * with underscore (_). They are introduced here as special chars.
538934SJose.Borrego@Sun.COM  */
548934SJose.Borrego@Sun.COM static char *special_chars = "[];=,+";
558934SJose.Borrego@Sun.COM 
568934SJose.Borrego@Sun.COM #define	isinvalid(c)	(strchr(invalid_dos_chars, c) || (c & 0x80))
578934SJose.Borrego@Sun.COM 
5812508Samw@Sun.COM static int smb_generate_mangle(uint64_t, char *, size_t);
5912508Samw@Sun.COM static char smb_mangle_char(char);
605331Samw 
615331Samw /*
628934SJose.Borrego@Sun.COM  * Return true if name contains characters that are invalid in a file
638934SJose.Borrego@Sun.COM  * name or it is a reserved DOS device name.  Otherwise, returns false.
645331Samw  *
658934SJose.Borrego@Sun.COM  * Control characters (values 0 - 31) and the following characters are
668934SJose.Borrego@Sun.COM  * invalid:
678934SJose.Borrego@Sun.COM  *	< > : " / \ | ? *
685331Samw  */
698934SJose.Borrego@Sun.COM boolean_t
smb_is_invalid_filename(const char * name)708934SJose.Borrego@Sun.COM smb_is_invalid_filename(const char *name)
715331Samw {
728934SJose.Borrego@Sun.COM 	const char *p;
735331Samw 
748934SJose.Borrego@Sun.COM 	if ((p = strpbrk(name, invalid_dos_chars)) != NULL) {
758934SJose.Borrego@Sun.COM 		if (*p != ' ')
768934SJose.Borrego@Sun.COM 			return (B_TRUE);
778934SJose.Borrego@Sun.COM 	}
788934SJose.Borrego@Sun.COM 
798934SJose.Borrego@Sun.COM 	return (smb_is_reserved_dos_name(name));
805331Samw }
815331Samw 
825331Samw /*
835331Samw  * smb_is_reserved_dos_name
845331Samw  *
858934SJose.Borrego@Sun.COM  * This function checks if the name is a reserved DOS device name.
868934SJose.Borrego@Sun.COM  * The device name should not be followed immediately by an extension,
878934SJose.Borrego@Sun.COM  * for example, NUL.txt.
885331Samw  */
89*12890SJoyce.McIntosh@Sun.COM boolean_t
smb_is_reserved_dos_name(const char * name)908934SJose.Borrego@Sun.COM smb_is_reserved_dos_name(const char *name)
915331Samw {
928934SJose.Borrego@Sun.COM 	static char *cnames[] = { "CLOCK$", "COM1", "COM2", "COM3", "COM4",
938934SJose.Borrego@Sun.COM 		"COM5", "COM6", "COM7", "COM8", "COM9", "CON" };
948934SJose.Borrego@Sun.COM 	static char *lnames[] = { "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
958934SJose.Borrego@Sun.COM 		"LPT6", "LPT7", "LPT8", "LPT9" };
968934SJose.Borrego@Sun.COM 	static char *others[] = { "AUX", "NUL", "PRN" };
978934SJose.Borrego@Sun.COM 	char	**reserved;
985331Samw 	char	ch;
998934SJose.Borrego@Sun.COM 	int	n_reserved;
1008934SJose.Borrego@Sun.COM 	int	len;
1018934SJose.Borrego@Sun.COM 	int	i;
1025331Samw 
10310966SJordan.Brown@Sun.COM 	ch = smb_toupper(*name);
1045331Samw 
1055331Samw 	switch (ch) {
1065331Samw 	case 'A':
1078934SJose.Borrego@Sun.COM 	case 'N':
1088934SJose.Borrego@Sun.COM 	case 'P':
1098934SJose.Borrego@Sun.COM 		reserved = others;
1108934SJose.Borrego@Sun.COM 		n_reserved = sizeof (others) / sizeof (others[0]);
1115331Samw 		break;
1128934SJose.Borrego@Sun.COM 	case 'C':
1138934SJose.Borrego@Sun.COM 		reserved = cnames;
1148934SJose.Borrego@Sun.COM 		n_reserved = sizeof (cnames) / sizeof (cnames[0]);
1155331Samw 		break;
1168934SJose.Borrego@Sun.COM 	case 'L':
1178934SJose.Borrego@Sun.COM 		reserved = lnames;
1188934SJose.Borrego@Sun.COM 		n_reserved = sizeof (lnames) / sizeof (lnames[0]);
1195331Samw 		break;
1208934SJose.Borrego@Sun.COM 	default:
1218934SJose.Borrego@Sun.COM 		return (B_FALSE);
1225331Samw 	}
1235331Samw 
1248934SJose.Borrego@Sun.COM 	for (i  = 0; i < n_reserved; ++i) {
1258934SJose.Borrego@Sun.COM 		len = strlen(reserved[i]);
1268934SJose.Borrego@Sun.COM 
12710966SJordan.Brown@Sun.COM 		if (smb_strcasecmp(reserved[i], name, len) == 0) {
1288934SJose.Borrego@Sun.COM 			ch = *(name + len);
1298934SJose.Borrego@Sun.COM 			if ((ch == '\0') || (ch == '.'))
1308934SJose.Borrego@Sun.COM 				return (B_TRUE);
1315331Samw 		}
1325331Samw 	}
1335331Samw 
1348934SJose.Borrego@Sun.COM 	return (B_FALSE);
1355331Samw }
1365331Samw 
1375331Samw /*
13812508Samw@Sun.COM  * smb_needs_mangled
1395331Samw  *
14012508Samw@Sun.COM  * A name needs to be mangled if any of the following are true:
14112508Samw@Sun.COM  * - the first character is dot (.) and the name is not "." or ".."
14212508Samw@Sun.COM  * - the name contains illegal or special charsacter
14312508Samw@Sun.COM  * - the name name length > 12
14412508Samw@Sun.COM  * - the number of dots == 0 and length > 8
14512508Samw@Sun.COM  * - the number of dots > 1
14612508Samw@Sun.COM  * - the number of dots == 1 and name is not 8.3
1475331Samw  */
14812508Samw@Sun.COM boolean_t
smb_needs_mangled(const char * name)14912508Samw@Sun.COM smb_needs_mangled(const char *name)
1505331Samw {
15112508Samw@Sun.COM 	int len, extlen, ndots;
15212508Samw@Sun.COM 	const char *p;
15312508Samw@Sun.COM 	const char *last_dot;
1545331Samw 
15512508Samw@Sun.COM 	if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
15612508Samw@Sun.COM 		return (B_FALSE);
1575331Samw 
1585331Samw 	if (*name == '.')
15912508Samw@Sun.COM 		return (B_TRUE);
1605331Samw 
16112508Samw@Sun.COM 	len = 0;
16212508Samw@Sun.COM 	ndots = 0;
16312508Samw@Sun.COM 	last_dot = NULL;
16412508Samw@Sun.COM 	for (p = name; *p != '\0'; ++p) {
16512508Samw@Sun.COM 		if (smb_iscntrl(*p) ||
16612508Samw@Sun.COM 		    (strchr(special_chars, *p) != NULL) ||
16712508Samw@Sun.COM 		    (strchr(invalid_dos_chars, *p)) != NULL)
16812508Samw@Sun.COM 			return (B_TRUE);
1695331Samw 
17012508Samw@Sun.COM 		if (*p == '.') {
17112508Samw@Sun.COM 			++ndots;
17212508Samw@Sun.COM 			last_dot = p;
17312508Samw@Sun.COM 		}
17412508Samw@Sun.COM 		++len;
1755331Samw 	}
1765331Samw 
17712508Samw@Sun.COM 	if ((len > SMB_NAME83_LEN) ||
17812508Samw@Sun.COM 	    (ndots == 0 && len > SMB_NAME83_BASELEN) ||
17912508Samw@Sun.COM 	    (ndots > 1)) {
18012508Samw@Sun.COM 		return (B_TRUE);
1815331Samw 	}
1825331Samw 
18312508Samw@Sun.COM 	if (last_dot != NULL) {
18412508Samw@Sun.COM 		extlen = strlen(last_dot + 1);
18512508Samw@Sun.COM 		if ((extlen == 0) || (extlen > SMB_NAME83_EXTLEN))
18612508Samw@Sun.COM 			return (B_TRUE);
1875331Samw 
18812508Samw@Sun.COM 		if ((len - extlen - 1) > SMB_NAME83_BASELEN)
18912508Samw@Sun.COM 			return (B_TRUE);
1905331Samw 	}
1915331Samw 
19212508Samw@Sun.COM 	return (B_FALSE);
1935331Samw }
1945331Samw 
1955331Samw /*
1965331Samw  * smb_mangle_char
1975331Samw  *
19812508Samw@Sun.COM  * If c is an invalid DOS character or non-ascii, it should
19912508Samw@Sun.COM  * not be used in the mangled name. We return -1 to indicate
20012508Samw@Sun.COM  * an invalid character.
2015331Samw  *
20212508Samw@Sun.COM  * If c is a special chars, it should be replaced with '_'.
2035331Samw  *
20412508Samw@Sun.COM  * Otherwise c is returned as uppercase.
2055331Samw  */
20612508Samw@Sun.COM static char
smb_mangle_char(char c)20712508Samw@Sun.COM smb_mangle_char(char c)
2085331Samw {
20912508Samw@Sun.COM 	if (isinvalid(c))
21012508Samw@Sun.COM 		return (-1);
2115331Samw 
21212508Samw@Sun.COM 	if (strchr(special_chars, c))
2135331Samw 		return ('_');
2145331Samw 
21512508Samw@Sun.COM 	return (smb_toupper(c));
2165331Samw }
2175331Samw 
2185331Samw /*
2195331Samw  * smb_generate_mangle
2205331Samw  *
22112508Samw@Sun.COM  * Generate a mangle string containing at least 2 characters and
22212508Samw@Sun.COM  * at most (buflen - 1) characters.
2235331Samw  *
2245331Samw  * Returns the number of chars in the generated mangle.
2255331Samw  */
2265331Samw static int
smb_generate_mangle(uint64_t fid,char * buf,size_t buflen)22712508Samw@Sun.COM smb_generate_mangle(uint64_t fid, char *buf, size_t buflen)
2285331Samw {
2295331Samw 	static char *base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
23012508Samw@Sun.COM 	char *p = buf;
2319437SJoyce.McIntosh@Sun.COM 	int i;
2329437SJoyce.McIntosh@Sun.COM 
2339437SJoyce.McIntosh@Sun.COM 	if (fid == 0)
2349437SJoyce.McIntosh@Sun.COM 		fid = (uint64_t)-1;
2355331Samw 
2369437SJoyce.McIntosh@Sun.COM 	*p++ = '~';
2379437SJoyce.McIntosh@Sun.COM 	for (i = 2; (i < buflen) && (fid > 0); fid /= 36, ++i)
2389437SJoyce.McIntosh@Sun.COM 		*p++ = base36[fid % 36];
2399437SJoyce.McIntosh@Sun.COM 	*p = '\0';
2405331Samw 
2419437SJoyce.McIntosh@Sun.COM 	return (i - 1);
2425331Samw }
2435331Samw 
2445331Samw /*
24512508Samw@Sun.COM  * smb_maybe_mangled
2465331Samw  *
2478934SJose.Borrego@Sun.COM  * Mangled names should be valid DOS file names: less than 12 characters
2488934SJose.Borrego@Sun.COM  * long, contain at least one tilde character and conform to an 8.3 name
2498934SJose.Borrego@Sun.COM  * format.
2505331Samw  *
2518934SJose.Borrego@Sun.COM  * Returns true if the name looks like a mangled name.
2525331Samw  */
25312508Samw@Sun.COM boolean_t
smb_maybe_mangled(char * name)25412508Samw@Sun.COM smb_maybe_mangled(char *name)
2555331Samw {
2568934SJose.Borrego@Sun.COM 	const char *p;
2578934SJose.Borrego@Sun.COM 	boolean_t has_tilde = B_FALSE;
2588934SJose.Borrego@Sun.COM 	int ndots = 0;
2598934SJose.Borrego@Sun.COM 	int i;
2608934SJose.Borrego@Sun.COM 
2618934SJose.Borrego@Sun.COM 	for (p = name, i = 0; (*p != '\0') && (i < SMB_NAME83_LEN); i++, p++) {
2628934SJose.Borrego@Sun.COM 		if ((strchr(special_chars, *p) != NULL) ||
2638934SJose.Borrego@Sun.COM 		    (strchr(invalid_dos_chars, *p) != NULL))
2648934SJose.Borrego@Sun.COM 			return (B_FALSE);
2655331Samw 
2668934SJose.Borrego@Sun.COM 		if (*p == '.') {
2678934SJose.Borrego@Sun.COM 			if ((++ndots) > 1)
2688934SJose.Borrego@Sun.COM 				return (B_FALSE);
2698934SJose.Borrego@Sun.COM 		}
2705331Samw 
2718934SJose.Borrego@Sun.COM 		if ((*p == '~') && (i < SMB_NAME83_BASELEN))
2728934SJose.Borrego@Sun.COM 			has_tilde = B_TRUE;
2738934SJose.Borrego@Sun.COM 
2748934SJose.Borrego@Sun.COM 		if (*p == '.' && !has_tilde)
2758934SJose.Borrego@Sun.COM 			return (B_FALSE);
2765331Samw 	}
2775331Samw 
27812508Samw@Sun.COM 	return ((*p == '\0') && has_tilde);
2795331Samw }
2805331Samw 
2815331Samw /*
28212508Samw@Sun.COM  * smb_mangle
2835331Samw  *
2845331Samw  * Microsoft knowledge base article #142982 describes how Windows
2855331Samw  * generates 8.3 filenames from long file names. Some other details
2865331Samw  * can be found in article #114816.
2875331Samw  *
28812508Samw@Sun.COM  * This function will mangle the name whether mangling is required
28912508Samw@Sun.COM  * or not. Callers should use smb_needs_mangled() to determine whether
29012508Samw@Sun.COM  * mangling is required.
2915331Samw  *
29212508Samw@Sun.COM  * name		original file name
29312508Samw@Sun.COM  * fid		inode number to generate unique mangle
29412508Samw@Sun.COM  * buf		output buffer (buflen bytes) to contain mangled name
2955331Samw  */
29612508Samw@Sun.COM void
smb_mangle(const char * name,ino64_t fid,char * buf,size_t buflen)29712508Samw@Sun.COM smb_mangle(const char *name, ino64_t fid, char *buf, size_t buflen)
29812508Samw@Sun.COM {
29912508Samw@Sun.COM 	int i, avail;
30012508Samw@Sun.COM 	const char *p;
30112508Samw@Sun.COM 	char c;
30212508Samw@Sun.COM 	char *pbuf;
30312508Samw@Sun.COM 	char mangle_buf[SMB_NAME83_BASELEN];
3045331Samw 
30512508Samw@Sun.COM 	ASSERT(name && buf && (buflen >= SMB_SHORTNAMELEN));
30612508Samw@Sun.COM 
30712508Samw@Sun.COM 	avail = SMB_NAME83_BASELEN -
30812508Samw@Sun.COM 	    smb_generate_mangle(fid, mangle_buf, SMB_NAME83_BASELEN);
30912508Samw@Sun.COM 	name += strspn(name, ".");
3105331Samw 
3115331Samw 	/*
31212508Samw@Sun.COM 	 * Copy up to avail characters from the base part of name
31312508Samw@Sun.COM 	 * to buf then append the generated mangle string.
3145331Samw 	 */
31512508Samw@Sun.COM 	p = name;
31612508Samw@Sun.COM 	pbuf = buf;
31712508Samw@Sun.COM 	for (i = 0; (i < avail) && (*p != '\0') && (*p != '.'); ++i, ++p) {
31812508Samw@Sun.COM 		if ((c = smb_mangle_char(*p)) == -1)
31912508Samw@Sun.COM 			continue;
32012508Samw@Sun.COM 		*pbuf++ = c;
3215331Samw 	}
32212508Samw@Sun.COM 	*pbuf = '\0';
32312508Samw@Sun.COM 	(void) strlcat(pbuf, mangle_buf, SMB_NAME83_BASELEN);
32412508Samw@Sun.COM 	pbuf = strchr(pbuf, '\0');
3255331Samw 
3265331Samw 	/*
32712508Samw@Sun.COM 	 * Find the last dot in the name. If there is a dot and an
32812508Samw@Sun.COM 	 * extension, append '.' and up to SMB_NAME83_EXTLEN extension
32912508Samw@Sun.COM 	 * characters to the mangled name.
3305331Samw 	 */
33112508Samw@Sun.COM 	if (((p = strrchr(name, '.')) != NULL) && (*(++p) != '\0')) {
33212508Samw@Sun.COM 		*pbuf++ = '.';
33312508Samw@Sun.COM 		for (i = 0; (i < SMB_NAME83_EXTLEN) && (*p != '\0'); ++i, ++p) {
33412508Samw@Sun.COM 			if ((c = smb_mangle_char(*p)) == -1)
33512508Samw@Sun.COM 				continue;
33612508Samw@Sun.COM 			*pbuf++ = c;
3375331Samw 		}
3385331Samw 	}
3395331Samw 
34012508Samw@Sun.COM 	*pbuf = '\0';
3415331Samw }
3425331Samw 
3435331Samw /*
34412508Samw@Sun.COM  * smb_unmangle
3455331Samw  *
3465331Samw  * Given a mangled name, try to find the real file name as it appears
3479231SAfshin.Ardakani@Sun.COM  * in the directory entry.
3489231SAfshin.Ardakani@Sun.COM  *
34912508Samw@Sun.COM  * smb_unmangle should only be called on names for which
35012508Samw@Sun.COM  * smb_maybe_mangled() is true
3519231SAfshin.Ardakani@Sun.COM  *
3529231SAfshin.Ardakani@Sun.COM  * File systems which support VFSFT_EDIRENT_FLAGS will return the
3539231SAfshin.Ardakani@Sun.COM  * directory entries as a buffer of edirent_t structure. Others will
3549231SAfshin.Ardakani@Sun.COM  * return a buffer of dirent64_t structures. A union is used for the
3559231SAfshin.Ardakani@Sun.COM  * the pointer into the buffer (bufptr, edp and dp).
3569231SAfshin.Ardakani@Sun.COM  * The ed_name/d_name is NULL terminated by the file system.
3575331Samw  *
3589231SAfshin.Ardakani@Sun.COM  * Returns:
3599231SAfshin.Ardakani@Sun.COM  *   0       - SUCCESS. Unmangled name is returned in namebuf.
3609231SAfshin.Ardakani@Sun.COM  *   EINVAL  - a parameter was invalid.
3619231SAfshin.Ardakani@Sun.COM  *   ENOTDIR - dnode is not a directory node.
3629231SAfshin.Ardakani@Sun.COM  *   ENOENT  - an unmangled name could not be found.
3635331Samw  */
3649231SAfshin.Ardakani@Sun.COM #define	SMB_UNMANGLE_BUFSIZE	(4 * 1024)
3659231SAfshin.Ardakani@Sun.COM int
smb_unmangle(smb_node_t * dnode,char * name,char * namebuf,int buflen,uint32_t flags)36612508Samw@Sun.COM smb_unmangle(smb_node_t *dnode, char *name, char *namebuf,
36710504SKeyur.Desai@Sun.COM     int buflen, uint32_t flags)
3689231SAfshin.Ardakani@Sun.COM {
3699231SAfshin.Ardakani@Sun.COM 	int		err, eof, bufsize, reclen;
3709231SAfshin.Ardakani@Sun.COM 	uint64_t	offset;
3719231SAfshin.Ardakani@Sun.COM 	ino64_t		ino;
3729231SAfshin.Ardakani@Sun.COM 	boolean_t	is_edp;
3739231SAfshin.Ardakani@Sun.COM 	char		*namep, *buf;
3749231SAfshin.Ardakani@Sun.COM 	char		shortname[SMB_SHORTNAMELEN];
3759231SAfshin.Ardakani@Sun.COM 	vnode_t		*vp;
3769231SAfshin.Ardakani@Sun.COM 	union {
3779231SAfshin.Ardakani@Sun.COM 		char		*bufptr;
3789231SAfshin.Ardakani@Sun.COM 		edirent_t	*edp;
3799231SAfshin.Ardakani@Sun.COM 		dirent64_t	*dp;
3809231SAfshin.Ardakani@Sun.COM 	} u;
3819231SAfshin.Ardakani@Sun.COM #define	bufptr	u.bufptr
3829231SAfshin.Ardakani@Sun.COM #define	edp		u.edp
3839231SAfshin.Ardakani@Sun.COM #define	dp		u.dp
3845331Samw 
3859231SAfshin.Ardakani@Sun.COM 	if (dnode == NULL || name == NULL || namebuf == NULL || buflen == 0)
3865331Samw 		return (EINVAL);
3875331Samw 
38812508Samw@Sun.COM 	ASSERT(smb_maybe_mangled(name) == B_TRUE);
3899231SAfshin.Ardakani@Sun.COM 
39011963SAfshin.Ardakani@Sun.COM 	if (!smb_node_is_dir(dnode))
3919231SAfshin.Ardakani@Sun.COM 		return (ENOTDIR);
3929231SAfshin.Ardakani@Sun.COM 
39311963SAfshin.Ardakani@Sun.COM 	vp = dnode->vp;
3949231SAfshin.Ardakani@Sun.COM 	*namebuf = '\0';
3959231SAfshin.Ardakani@Sun.COM 	is_edp = vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS);
3965331Samw 
3979231SAfshin.Ardakani@Sun.COM 	buf = kmem_alloc(SMB_UNMANGLE_BUFSIZE, KM_SLEEP);
3989231SAfshin.Ardakani@Sun.COM 	bufsize = SMB_UNMANGLE_BUFSIZE;
3999231SAfshin.Ardakani@Sun.COM 	offset = 0;
4009231SAfshin.Ardakani@Sun.COM 
4019231SAfshin.Ardakani@Sun.COM 	while ((err = smb_vop_readdir(vp, offset, buf, &bufsize,
40210504SKeyur.Desai@Sun.COM 	    &eof, flags, kcred)) == 0) {
4039231SAfshin.Ardakani@Sun.COM 		if (bufsize == 0) {
4049231SAfshin.Ardakani@Sun.COM 			err = ENOENT;
4059231SAfshin.Ardakani@Sun.COM 			break;
4065331Samw 		}
4075331Samw 
4089231SAfshin.Ardakani@Sun.COM 		bufptr = buf;
4099231SAfshin.Ardakani@Sun.COM 		reclen = 0;
4109231SAfshin.Ardakani@Sun.COM 
4119231SAfshin.Ardakani@Sun.COM 		while ((bufptr += reclen) < buf + bufsize) {
4129231SAfshin.Ardakani@Sun.COM 			if (is_edp) {
4139231SAfshin.Ardakani@Sun.COM 				reclen = edp->ed_reclen;
4149231SAfshin.Ardakani@Sun.COM 				offset = edp->ed_off;
4159231SAfshin.Ardakani@Sun.COM 				ino = edp->ed_ino;
4169231SAfshin.Ardakani@Sun.COM 				namep = edp->ed_name;
4179231SAfshin.Ardakani@Sun.COM 			} else {
4189231SAfshin.Ardakani@Sun.COM 				reclen = dp->d_reclen;
4199231SAfshin.Ardakani@Sun.COM 				offset = dp->d_off;
4209231SAfshin.Ardakani@Sun.COM 				ino = dp->d_ino;
4219231SAfshin.Ardakani@Sun.COM 				namep = dp->d_name;
4229231SAfshin.Ardakani@Sun.COM 			}
4235331Samw 
42410966SJordan.Brown@Sun.COM 			/* skip non utf8 filename */
42510966SJordan.Brown@Sun.COM 			if (u8_validate(namep, strlen(namep), NULL,
42610966SJordan.Brown@Sun.COM 			    U8_VALIDATE_ENTIRE, &err) < 0)
42710966SJordan.Brown@Sun.COM 				continue;
42810966SJordan.Brown@Sun.COM 
42912508Samw@Sun.COM 			smb_mangle(namep, ino, shortname, SMB_SHORTNAMELEN);
4305331Samw 
43110966SJordan.Brown@Sun.COM 			if (smb_strcasecmp(name, shortname, 0) == 0) {
4329231SAfshin.Ardakani@Sun.COM 				(void) strlcpy(namebuf, namep, buflen);
4339231SAfshin.Ardakani@Sun.COM 				kmem_free(buf, SMB_UNMANGLE_BUFSIZE);
4349231SAfshin.Ardakani@Sun.COM 				return (0);
4359231SAfshin.Ardakani@Sun.COM 			}
4369231SAfshin.Ardakani@Sun.COM 		}
4379231SAfshin.Ardakani@Sun.COM 
4389231SAfshin.Ardakani@Sun.COM 		if (eof) {
4399231SAfshin.Ardakani@Sun.COM 			err = ENOENT;
4409231SAfshin.Ardakani@Sun.COM 			break;
4419231SAfshin.Ardakani@Sun.COM 		}
4429231SAfshin.Ardakani@Sun.COM 
4439231SAfshin.Ardakani@Sun.COM 		bufsize = SMB_UNMANGLE_BUFSIZE;
4445331Samw 	}
4455331Samw 
4469231SAfshin.Ardakani@Sun.COM 	kmem_free(buf, SMB_UNMANGLE_BUFSIZE);
4479231SAfshin.Ardakani@Sun.COM 	return (err);
4485331Samw }
449