xref: /onnv-gate/usr/src/common/smbsrv/smb_string.c (revision 11963:061945695ce1)
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 /*
22*11963SAfshin.Ardakani@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw #ifdef _KERNEL
275331Samw #include <sys/types.h>
285331Samw #include <sys/sunddi.h>
295331Samw #else
3010966SJordan.Brown@Sun.COM #include <stdio.h>
315331Samw #include <stdlib.h>
325331Samw #include <string.h>
335331Samw #include <strings.h>
345331Samw #endif
3510966SJordan.Brown@Sun.COM #include <sys/u8_textprep.h>
3610966SJordan.Brown@Sun.COM #include <smbsrv/alloc.h>
37*11963SAfshin.Ardakani@Sun.COM #include <sys/errno.h>
385331Samw #include <smbsrv/string.h>
3910966SJordan.Brown@Sun.COM #include <smbsrv/cp_usascii.h>
4010966SJordan.Brown@Sun.COM #include <smbsrv/cp_unicode.h>
4110966SJordan.Brown@Sun.COM 
4210966SJordan.Brown@Sun.COM #define	UNICODE_N_ENTRIES	(sizeof (a_unicode) / sizeof (a_unicode[0]))
435331Samw 
4410966SJordan.Brown@Sun.COM /*
4510966SJordan.Brown@Sun.COM  * Global pointer to the current codepage: defaults to ASCII,
4610966SJordan.Brown@Sun.COM  * and a flag indicating whether the codepage is Unicode or ASCII.
4710966SJordan.Brown@Sun.COM  */
4810966SJordan.Brown@Sun.COM static smb_codepage_t *current_codepage = usascii_codepage;
4910966SJordan.Brown@Sun.COM static boolean_t is_unicode = B_FALSE;
5010966SJordan.Brown@Sun.COM 
5110966SJordan.Brown@Sun.COM static smb_codepage_t *smb_unicode_init(void);
525331Samw 
535331Samw /*
545331Samw  * strsubst
555331Samw  *
565331Samw  * Scan a string replacing all occurrences of orgchar with newchar.
575331Samw  * Returns a pointer to s, or null of s is null.
585331Samw  */
595331Samw char *
strsubst(char * s,char orgchar,char newchar)605331Samw strsubst(char *s, char orgchar, char newchar)
615331Samw {
625331Samw 	char *p = s;
635331Samw 
645331Samw 	if (p == 0)
655331Samw 		return (0);
665331Samw 
675331Samw 	while (*p) {
685331Samw 		if (*p == orgchar)
695331Samw 			*p = newchar;
705331Samw 		++p;
715331Samw 	}
725331Samw 
735331Samw 	return (s);
745331Samw }
755331Samw 
765331Samw /*
775331Samw  * strcanon
785331Samw  *
795331Samw  * Normalize a string by reducing all the repeated characters in
805331Samw  * buf as defined by class. For example;
815331Samw  *
825331Samw  *		char *buf = strdup("/d1//d2//d3\\\\d4\\\\f1.txt");
835331Samw  *		strcanon(buf, "/\\");
845331Samw  *
855331Samw  * Would result in buf containing the following string:
865331Samw  *
875331Samw  *		/d1/d2/d3\d4\f1.txt
885331Samw  *
895331Samw  * This function modifies the contents of buf in place and returns
905331Samw  * a pointer to buf.
915331Samw  */
925331Samw char *
strcanon(char * buf,const char * class)935331Samw strcanon(char *buf, const char *class)
945331Samw {
955331Samw 	char *p = buf;
965331Samw 	char *q = buf;
975331Samw 	char *r;
985331Samw 
995331Samw 	while (*p) {
1005331Samw 		*q++ = *p;
1015331Samw 
1025331Samw 		if ((r = strchr(class, *p)) != 0) {
1035331Samw 			while (*p == *r)
1045331Samw 				++p;
1055331Samw 		} else
1065331Samw 			++p;
1075331Samw 	}
1085331Samw 
1095331Samw 	*q = '\0';
1105331Samw 	return (buf);
1115331Samw }
11210966SJordan.Brown@Sun.COM 
11310966SJordan.Brown@Sun.COM void
smb_codepage_init(void)11410966SJordan.Brown@Sun.COM smb_codepage_init(void)
11510966SJordan.Brown@Sun.COM {
11610966SJordan.Brown@Sun.COM 	smb_codepage_t *cp;
11710966SJordan.Brown@Sun.COM 
11810966SJordan.Brown@Sun.COM 	if (is_unicode)
11910966SJordan.Brown@Sun.COM 		return;
12010966SJordan.Brown@Sun.COM 
12110966SJordan.Brown@Sun.COM 	if ((cp = smb_unicode_init()) != NULL) {
12210966SJordan.Brown@Sun.COM 		current_codepage = cp;
12310966SJordan.Brown@Sun.COM 		is_unicode = B_TRUE;
12410966SJordan.Brown@Sun.COM 	} else {
12510966SJordan.Brown@Sun.COM 		current_codepage = usascii_codepage;
12610966SJordan.Brown@Sun.COM 		is_unicode = B_FALSE;
12710966SJordan.Brown@Sun.COM 	}
12810966SJordan.Brown@Sun.COM }
12910966SJordan.Brown@Sun.COM 
13010966SJordan.Brown@Sun.COM /*
13110966SJordan.Brown@Sun.COM  * Determine whether or not a character is an uppercase character.
13210966SJordan.Brown@Sun.COM  * This function operates on the current codepage table. Returns
13310966SJordan.Brown@Sun.COM  * non-zero if the character is uppercase. Otherwise returns zero.
13410966SJordan.Brown@Sun.COM  */
13510966SJordan.Brown@Sun.COM int
smb_isupper(int c)13610966SJordan.Brown@Sun.COM smb_isupper(int c)
13710966SJordan.Brown@Sun.COM {
13810966SJordan.Brown@Sun.COM 	uint16_t mask = is_unicode ? 0xffff : 0xff;
13910966SJordan.Brown@Sun.COM 
14010966SJordan.Brown@Sun.COM 	return (current_codepage[c & mask].ctype & CODEPAGE_ISUPPER);
14110966SJordan.Brown@Sun.COM }
14210966SJordan.Brown@Sun.COM 
14310966SJordan.Brown@Sun.COM /*
14410966SJordan.Brown@Sun.COM  * Determine whether or not a character is an lowercase character.
14510966SJordan.Brown@Sun.COM  * This function operates on the current codepage table. Returns
14610966SJordan.Brown@Sun.COM  * non-zero if the character is lowercase. Otherwise returns zero.
14710966SJordan.Brown@Sun.COM  */
14810966SJordan.Brown@Sun.COM int
smb_islower(int c)14910966SJordan.Brown@Sun.COM smb_islower(int c)
15010966SJordan.Brown@Sun.COM {
15110966SJordan.Brown@Sun.COM 	uint16_t mask = is_unicode ? 0xffff : 0xff;
15210966SJordan.Brown@Sun.COM 
15310966SJordan.Brown@Sun.COM 	return (current_codepage[c & mask].ctype & CODEPAGE_ISLOWER);
15410966SJordan.Brown@Sun.COM }
15510966SJordan.Brown@Sun.COM 
15610966SJordan.Brown@Sun.COM /*
15710966SJordan.Brown@Sun.COM  * Convert individual characters to their uppercase equivalent value.
15810966SJordan.Brown@Sun.COM  * If the specified character is lowercase, the uppercase value will
15910966SJordan.Brown@Sun.COM  * be returned. Otherwise the original value will be returned.
16010966SJordan.Brown@Sun.COM  */
16110966SJordan.Brown@Sun.COM int
smb_toupper(int c)16210966SJordan.Brown@Sun.COM smb_toupper(int c)
16310966SJordan.Brown@Sun.COM {
16410966SJordan.Brown@Sun.COM 	uint16_t mask = is_unicode ? 0xffff : 0xff;
16510966SJordan.Brown@Sun.COM 
16610966SJordan.Brown@Sun.COM 	return (current_codepage[c & mask].upper);
16710966SJordan.Brown@Sun.COM }
16810966SJordan.Brown@Sun.COM 
16910966SJordan.Brown@Sun.COM /*
17010966SJordan.Brown@Sun.COM  * Convert individual characters to their lowercase equivalent value.
17110966SJordan.Brown@Sun.COM  * If the specified character is uppercase, the lowercase value will
17210966SJordan.Brown@Sun.COM  * be returned. Otherwise the original value will be returned.
17310966SJordan.Brown@Sun.COM  */
17410966SJordan.Brown@Sun.COM int
smb_tolower(int c)17510966SJordan.Brown@Sun.COM smb_tolower(int c)
17610966SJordan.Brown@Sun.COM {
17710966SJordan.Brown@Sun.COM 	uint16_t mask = is_unicode ? 0xffff : 0xff;
17810966SJordan.Brown@Sun.COM 
17910966SJordan.Brown@Sun.COM 	return (current_codepage[c & mask].lower);
18010966SJordan.Brown@Sun.COM }
18110966SJordan.Brown@Sun.COM 
18210966SJordan.Brown@Sun.COM /*
18310966SJordan.Brown@Sun.COM  * Convert a string to uppercase using the appropriate codepage. The
18410966SJordan.Brown@Sun.COM  * string is converted in place. A pointer to the string is returned.
18510966SJordan.Brown@Sun.COM  * There is an assumption here that uppercase and lowercase values
18610966SJordan.Brown@Sun.COM  * always result encode to the same length.
18710966SJordan.Brown@Sun.COM  */
18810966SJordan.Brown@Sun.COM char *
smb_strupr(char * s)18910966SJordan.Brown@Sun.COM smb_strupr(char *s)
19010966SJordan.Brown@Sun.COM {
19110966SJordan.Brown@Sun.COM 	smb_wchar_t c;
19210966SJordan.Brown@Sun.COM 	char *p = s;
19310966SJordan.Brown@Sun.COM 
19410966SJordan.Brown@Sun.COM 	while (*p) {
19510966SJordan.Brown@Sun.COM 		if (smb_isascii(*p)) {
19610966SJordan.Brown@Sun.COM 			*p = smb_toupper(*p);
19710966SJordan.Brown@Sun.COM 			p++;
19810966SJordan.Brown@Sun.COM 		} else {
19910966SJordan.Brown@Sun.COM 			if (smb_mbtowc(&c, p, MTS_MB_CHAR_MAX) < 0)
20010966SJordan.Brown@Sun.COM 				return (0);
20110966SJordan.Brown@Sun.COM 
20210966SJordan.Brown@Sun.COM 			if (c == 0)
20310966SJordan.Brown@Sun.COM 				break;
20410966SJordan.Brown@Sun.COM 
20510966SJordan.Brown@Sun.COM 			c = smb_toupper(c);
20610966SJordan.Brown@Sun.COM 			p += smb_wctomb(p, c);
20710966SJordan.Brown@Sun.COM 		}
20810966SJordan.Brown@Sun.COM 	}
20910966SJordan.Brown@Sun.COM 
21010966SJordan.Brown@Sun.COM 	return (s);
21110966SJordan.Brown@Sun.COM }
21210966SJordan.Brown@Sun.COM 
21310966SJordan.Brown@Sun.COM /*
21410966SJordan.Brown@Sun.COM  * Convert a string to lowercase using the appropriate codepage. The
21510966SJordan.Brown@Sun.COM  * string is converted in place. A pointer to the string is returned.
21610966SJordan.Brown@Sun.COM  * There is an assumption here that uppercase and lowercase values
21710966SJordan.Brown@Sun.COM  * always result encode to the same length.
21810966SJordan.Brown@Sun.COM  */
21910966SJordan.Brown@Sun.COM char *
smb_strlwr(char * s)22010966SJordan.Brown@Sun.COM smb_strlwr(char *s)
22110966SJordan.Brown@Sun.COM {
22210966SJordan.Brown@Sun.COM 	smb_wchar_t c;
22310966SJordan.Brown@Sun.COM 	char *p = s;
22410966SJordan.Brown@Sun.COM 
22510966SJordan.Brown@Sun.COM 	while (*p) {
22610966SJordan.Brown@Sun.COM 		if (smb_isascii(*p)) {
22710966SJordan.Brown@Sun.COM 			*p = smb_tolower(*p);
22810966SJordan.Brown@Sun.COM 			p++;
22910966SJordan.Brown@Sun.COM 		} else {
23010966SJordan.Brown@Sun.COM 			if (smb_mbtowc(&c, p, MTS_MB_CHAR_MAX) < 0)
23110966SJordan.Brown@Sun.COM 				return (0);
23210966SJordan.Brown@Sun.COM 
23310966SJordan.Brown@Sun.COM 			if (c == 0)
23410966SJordan.Brown@Sun.COM 				break;
23510966SJordan.Brown@Sun.COM 
23610966SJordan.Brown@Sun.COM 			c = smb_tolower(c);
23710966SJordan.Brown@Sun.COM 			p += smb_wctomb(p, c);
23810966SJordan.Brown@Sun.COM 		}
23910966SJordan.Brown@Sun.COM 	}
24010966SJordan.Brown@Sun.COM 
24110966SJordan.Brown@Sun.COM 	return (s);
24210966SJordan.Brown@Sun.COM }
24310966SJordan.Brown@Sun.COM 
24410966SJordan.Brown@Sun.COM /*
24510966SJordan.Brown@Sun.COM  * Returns 1 if string contains NO uppercase chars 0 otherwise. However,
24610966SJordan.Brown@Sun.COM  * -1 is returned if "s" is not a valid multi-byte string.
24710966SJordan.Brown@Sun.COM  */
24810966SJordan.Brown@Sun.COM int
smb_isstrlwr(const char * s)24910966SJordan.Brown@Sun.COM smb_isstrlwr(const char *s)
25010966SJordan.Brown@Sun.COM {
25110966SJordan.Brown@Sun.COM 	smb_wchar_t c;
25210966SJordan.Brown@Sun.COM 	int n;
25310966SJordan.Brown@Sun.COM 	const char *p = s;
25410966SJordan.Brown@Sun.COM 
25510966SJordan.Brown@Sun.COM 	while (*p) {
25610966SJordan.Brown@Sun.COM 		if (smb_isascii(*p) && smb_isupper(*p))
25710966SJordan.Brown@Sun.COM 			return (0);
25810966SJordan.Brown@Sun.COM 		else {
25910966SJordan.Brown@Sun.COM 			if ((n = smb_mbtowc(&c, p, MTS_MB_CHAR_MAX)) < 0)
26010966SJordan.Brown@Sun.COM 				return (-1);
26110966SJordan.Brown@Sun.COM 
26210966SJordan.Brown@Sun.COM 			if (c == 0)
26310966SJordan.Brown@Sun.COM 				break;
26410966SJordan.Brown@Sun.COM 
26510966SJordan.Brown@Sun.COM 			if (smb_isupper(c))
26610966SJordan.Brown@Sun.COM 				return (0);
26710966SJordan.Brown@Sun.COM 
26810966SJordan.Brown@Sun.COM 			p += n;
26910966SJordan.Brown@Sun.COM 		}
27010966SJordan.Brown@Sun.COM 	}
27110966SJordan.Brown@Sun.COM 
27210966SJordan.Brown@Sun.COM 	return (1);
27310966SJordan.Brown@Sun.COM }
27410966SJordan.Brown@Sun.COM 
27510966SJordan.Brown@Sun.COM /*
27610966SJordan.Brown@Sun.COM  * Returns 1 if string contains NO lowercase chars 0 otherwise. However,
27710966SJordan.Brown@Sun.COM  * -1 is returned if "s" is not a valid multi-byte string.
27810966SJordan.Brown@Sun.COM  */
27910966SJordan.Brown@Sun.COM int
smb_isstrupr(const char * s)28010966SJordan.Brown@Sun.COM smb_isstrupr(const char *s)
28110966SJordan.Brown@Sun.COM {
28210966SJordan.Brown@Sun.COM 	smb_wchar_t c;
28310966SJordan.Brown@Sun.COM 	int n;
28410966SJordan.Brown@Sun.COM 	const char *p = s;
28510966SJordan.Brown@Sun.COM 
28610966SJordan.Brown@Sun.COM 	while (*p) {
28710966SJordan.Brown@Sun.COM 		if (smb_isascii(*p) && smb_islower(*p))
28810966SJordan.Brown@Sun.COM 			return (0);
28910966SJordan.Brown@Sun.COM 		else {
29010966SJordan.Brown@Sun.COM 			if ((n = smb_mbtowc(&c, p, MTS_MB_CHAR_MAX)) < 0)
29110966SJordan.Brown@Sun.COM 				return (-1);
29210966SJordan.Brown@Sun.COM 
29310966SJordan.Brown@Sun.COM 			if (c == 0)
29410966SJordan.Brown@Sun.COM 				break;
29510966SJordan.Brown@Sun.COM 
29610966SJordan.Brown@Sun.COM 			if (smb_islower(c))
29710966SJordan.Brown@Sun.COM 				return (0);
29810966SJordan.Brown@Sun.COM 
29910966SJordan.Brown@Sun.COM 			p += n;
30010966SJordan.Brown@Sun.COM 		}
30110966SJordan.Brown@Sun.COM 	}
30210966SJordan.Brown@Sun.COM 
30310966SJordan.Brown@Sun.COM 	return (1);
30410966SJordan.Brown@Sun.COM }
30510966SJordan.Brown@Sun.COM 
30610966SJordan.Brown@Sun.COM /*
30710966SJordan.Brown@Sun.COM  * Compare the null-terminated strings s1 and s2 and return an integer
30810966SJordan.Brown@Sun.COM  * greater than, equal to or less than 0 dependent on whether s1 is
30910966SJordan.Brown@Sun.COM  * lexicographically greater than, equal to or less than s2 after
31010966SJordan.Brown@Sun.COM  * translation of each character to lowercase.  The original strings
31110966SJordan.Brown@Sun.COM  * are not modified.
31210966SJordan.Brown@Sun.COM  *
31310966SJordan.Brown@Sun.COM  * If n is non-zero, at most n bytes are compared.  Otherwise, the strings
31410966SJordan.Brown@Sun.COM  * are compared until a null terminator is encountered.
31510966SJordan.Brown@Sun.COM  *
31610966SJordan.Brown@Sun.COM  * Out:    0 if strings are equal
31710966SJordan.Brown@Sun.COM  *       < 0 if first string < second string
31810966SJordan.Brown@Sun.COM  *       > 0 if first string > second string
31910966SJordan.Brown@Sun.COM  */
32010966SJordan.Brown@Sun.COM int
smb_strcasecmp(const char * s1,const char * s2,size_t n)32110966SJordan.Brown@Sun.COM smb_strcasecmp(const char *s1, const char *s2, size_t n)
32210966SJordan.Brown@Sun.COM {
32310966SJordan.Brown@Sun.COM 	int	err = 0;
32410966SJordan.Brown@Sun.COM 	int	rc;
32510966SJordan.Brown@Sun.COM 
32610966SJordan.Brown@Sun.COM 	rc = u8_strcmp(s1, s2, n, U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err);
32710966SJordan.Brown@Sun.COM 	if (err != 0)
32810966SJordan.Brown@Sun.COM 		return (-1);
32910966SJordan.Brown@Sun.COM 	return (rc);
33010966SJordan.Brown@Sun.COM }
33110966SJordan.Brown@Sun.COM 
33210966SJordan.Brown@Sun.COM /*
33310966SJordan.Brown@Sun.COM  * First build a codepage based on cp_unicode.h.  Then build the unicode
33410966SJordan.Brown@Sun.COM  * codepage from this interim codepage by copying the entries over while
33510966SJordan.Brown@Sun.COM  * fixing them and filling in the gaps.
33610966SJordan.Brown@Sun.COM  */
33710966SJordan.Brown@Sun.COM static smb_codepage_t *
smb_unicode_init(void)33810966SJordan.Brown@Sun.COM smb_unicode_init(void)
33910966SJordan.Brown@Sun.COM {
34010966SJordan.Brown@Sun.COM 	smb_codepage_t	*unicode;
34110966SJordan.Brown@Sun.COM 	uint32_t	a = 0;
34210966SJordan.Brown@Sun.COM 	uint32_t	b = 0;
34310966SJordan.Brown@Sun.COM 
34410966SJordan.Brown@Sun.COM 	unicode = MEM_ZALLOC("unicode", sizeof (smb_codepage_t) << 16);
34510966SJordan.Brown@Sun.COM 	if (unicode == NULL)
34610966SJordan.Brown@Sun.COM 		return (NULL);
34710966SJordan.Brown@Sun.COM 
34810966SJordan.Brown@Sun.COM 	while (b != 0xffff) {
34910966SJordan.Brown@Sun.COM 		/*
35010966SJordan.Brown@Sun.COM 		 * If there is a gap in the standard,
35110966SJordan.Brown@Sun.COM 		 * fill in the gap with no-case entries.
35210966SJordan.Brown@Sun.COM 		 */
35310966SJordan.Brown@Sun.COM 		if (UNICODE_N_ENTRIES <= a || a_unicode[a].val > b) {
35410966SJordan.Brown@Sun.COM 			unicode[b].ctype = CODEPAGE_ISNONE;
35510966SJordan.Brown@Sun.COM 			unicode[b].upper = (smb_wchar_t)b;
35610966SJordan.Brown@Sun.COM 			unicode[b].lower = (smb_wchar_t)b;
35710966SJordan.Brown@Sun.COM 			b++;
35810966SJordan.Brown@Sun.COM 			continue;
35910966SJordan.Brown@Sun.COM 		}
36010966SJordan.Brown@Sun.COM 
36110966SJordan.Brown@Sun.COM 		/*
36210966SJordan.Brown@Sun.COM 		 * Copy the entry and fixup as required.
36310966SJordan.Brown@Sun.COM 		 */
36410966SJordan.Brown@Sun.COM 		switch (a_unicode[a].ctype) {
36510966SJordan.Brown@Sun.COM 		case CODEPAGE_ISNONE:
36610966SJordan.Brown@Sun.COM 			/*
36710966SJordan.Brown@Sun.COM 			 * Replace 0xffff in upper/lower fields with its val.
36810966SJordan.Brown@Sun.COM 			 */
36910966SJordan.Brown@Sun.COM 			unicode[b].ctype = CODEPAGE_ISNONE;
37010966SJordan.Brown@Sun.COM 			unicode[b].upper = (smb_wchar_t)b;
37110966SJordan.Brown@Sun.COM 			unicode[b].lower = (smb_wchar_t)b;
37210966SJordan.Brown@Sun.COM 			break;
37310966SJordan.Brown@Sun.COM 		case CODEPAGE_ISUPPER:
37410966SJordan.Brown@Sun.COM 			/*
37510966SJordan.Brown@Sun.COM 			 * Some characters may have case yet not have
37610966SJordan.Brown@Sun.COM 			 * case conversion.  Treat them as no-case.
37710966SJordan.Brown@Sun.COM 			 */
37810966SJordan.Brown@Sun.COM 			if (a_unicode[a].lower == 0xffff) {
37910966SJordan.Brown@Sun.COM 				unicode[b].ctype = CODEPAGE_ISNONE;
38010966SJordan.Brown@Sun.COM 				unicode[b].upper = (smb_wchar_t)b;
38110966SJordan.Brown@Sun.COM 				unicode[b].lower = (smb_wchar_t)b;
38210966SJordan.Brown@Sun.COM 			} else {
38310966SJordan.Brown@Sun.COM 				unicode[b].ctype = CODEPAGE_ISUPPER;
38410966SJordan.Brown@Sun.COM 				unicode[b].upper = (smb_wchar_t)b;
38510966SJordan.Brown@Sun.COM 				unicode[b].lower = a_unicode[a].lower;
38610966SJordan.Brown@Sun.COM 			}
38710966SJordan.Brown@Sun.COM 			break;
38810966SJordan.Brown@Sun.COM 		case CODEPAGE_ISLOWER:
38910966SJordan.Brown@Sun.COM 			/*
39010966SJordan.Brown@Sun.COM 			 * Some characters may have case yet not have
39110966SJordan.Brown@Sun.COM 			 * case conversion.  Treat them as no-case.
39210966SJordan.Brown@Sun.COM 			 */
39310966SJordan.Brown@Sun.COM 			if (a_unicode[a].upper == 0xffff) {
39410966SJordan.Brown@Sun.COM 				unicode[b].ctype = CODEPAGE_ISNONE;
39510966SJordan.Brown@Sun.COM 				unicode[b].upper = (smb_wchar_t)b;
39610966SJordan.Brown@Sun.COM 				unicode[b].lower = (smb_wchar_t)b;
39710966SJordan.Brown@Sun.COM 			} else {
39810966SJordan.Brown@Sun.COM 				unicode[b].ctype = CODEPAGE_ISLOWER;
39910966SJordan.Brown@Sun.COM 				unicode[b].upper = a_unicode[a].upper;
40010966SJordan.Brown@Sun.COM 				unicode[b].lower = (smb_wchar_t)b;
40110966SJordan.Brown@Sun.COM 			}
40210966SJordan.Brown@Sun.COM 			break;
40310966SJordan.Brown@Sun.COM 		default:
40410966SJordan.Brown@Sun.COM 			MEM_FREE("unicode", unicode);
40510966SJordan.Brown@Sun.COM 			return (NULL);
40610966SJordan.Brown@Sun.COM 		}
40710966SJordan.Brown@Sun.COM 
40810966SJordan.Brown@Sun.COM 		a++;
40910966SJordan.Brown@Sun.COM 		b++;
41010966SJordan.Brown@Sun.COM 	};
41110966SJordan.Brown@Sun.COM 
41210966SJordan.Brown@Sun.COM 	return (unicode);
41310966SJordan.Brown@Sun.COM }
414*11963SAfshin.Ardakani@Sun.COM 
415*11963SAfshin.Ardakani@Sun.COM /*
416*11963SAfshin.Ardakani@Sun.COM  * Parse a UNC path (\\server\share\path) into its components.
417*11963SAfshin.Ardakani@Sun.COM  * Although a standard UNC path starts with two '\', in DFS
418*11963SAfshin.Ardakani@Sun.COM  * all UNC paths start with one '\'. So, this function only
419*11963SAfshin.Ardakani@Sun.COM  * checks for one.
420*11963SAfshin.Ardakani@Sun.COM  *
421*11963SAfshin.Ardakani@Sun.COM  * A valid UNC must at least contain two components i.e. server
422*11963SAfshin.Ardakani@Sun.COM  * and share. The path is parsed to:
423*11963SAfshin.Ardakani@Sun.COM  *
424*11963SAfshin.Ardakani@Sun.COM  * unc_server	server or domain name with no leading/trailing '\'
425*11963SAfshin.Ardakani@Sun.COM  * unc_share	share name with no leading/trailing '\'
426*11963SAfshin.Ardakani@Sun.COM  * unc_path	relative path to the share with no leading/trailing '\'
427*11963SAfshin.Ardakani@Sun.COM  * 		it is valid for unc_path to be NULL.
428*11963SAfshin.Ardakani@Sun.COM  *
429*11963SAfshin.Ardakani@Sun.COM  * Upon successful return of this function, smb_unc_free()
430*11963SAfshin.Ardakani@Sun.COM  * MUST be called when returned 'unc' is no longer needed.
431*11963SAfshin.Ardakani@Sun.COM  *
432*11963SAfshin.Ardakani@Sun.COM  * Returns 0 on success, otherwise returns an errno code.
433*11963SAfshin.Ardakani@Sun.COM  */
434*11963SAfshin.Ardakani@Sun.COM int
smb_unc_init(const char * path,smb_unc_t * unc)435*11963SAfshin.Ardakani@Sun.COM smb_unc_init(const char *path, smb_unc_t *unc)
436*11963SAfshin.Ardakani@Sun.COM {
437*11963SAfshin.Ardakani@Sun.COM 	char *p;
438*11963SAfshin.Ardakani@Sun.COM 
439*11963SAfshin.Ardakani@Sun.COM 	if (path == NULL || unc == NULL || (*path != '\\' && *path != '/'))
440*11963SAfshin.Ardakani@Sun.COM 		return (EINVAL);
441*11963SAfshin.Ardakani@Sun.COM 
442*11963SAfshin.Ardakani@Sun.COM 	bzero(unc, sizeof (smb_unc_t));
443*11963SAfshin.Ardakani@Sun.COM 
444*11963SAfshin.Ardakani@Sun.COM #ifdef _KERNEL
445*11963SAfshin.Ardakani@Sun.COM 	unc->unc_buf = smb_mem_strdup(path);
446*11963SAfshin.Ardakani@Sun.COM #else
447*11963SAfshin.Ardakani@Sun.COM 	if ((unc->unc_buf = strdup(path)) == NULL)
448*11963SAfshin.Ardakani@Sun.COM 		return (ENOMEM);
449*11963SAfshin.Ardakani@Sun.COM #endif
450*11963SAfshin.Ardakani@Sun.COM 
451*11963SAfshin.Ardakani@Sun.COM 	(void) strsubst(unc->unc_buf, '\\', '/');
452*11963SAfshin.Ardakani@Sun.COM 	(void) strcanon(unc->unc_buf, "/");
453*11963SAfshin.Ardakani@Sun.COM 
454*11963SAfshin.Ardakani@Sun.COM 	unc->unc_server = unc->unc_buf + 1;
455*11963SAfshin.Ardakani@Sun.COM 	if (*unc->unc_server == '\0') {
456*11963SAfshin.Ardakani@Sun.COM 		smb_unc_free(unc);
457*11963SAfshin.Ardakani@Sun.COM 		return (EINVAL);
458*11963SAfshin.Ardakani@Sun.COM 	}
459*11963SAfshin.Ardakani@Sun.COM 
460*11963SAfshin.Ardakani@Sun.COM 	if ((p = strchr(unc->unc_server, '/')) == NULL) {
461*11963SAfshin.Ardakani@Sun.COM 		smb_unc_free(unc);
462*11963SAfshin.Ardakani@Sun.COM 		return (EINVAL);
463*11963SAfshin.Ardakani@Sun.COM 	}
464*11963SAfshin.Ardakani@Sun.COM 
465*11963SAfshin.Ardakani@Sun.COM 	*p++ = '\0';
466*11963SAfshin.Ardakani@Sun.COM 	unc->unc_share = p;
467*11963SAfshin.Ardakani@Sun.COM 
468*11963SAfshin.Ardakani@Sun.COM 	if (*unc->unc_share == '\0') {
469*11963SAfshin.Ardakani@Sun.COM 		smb_unc_free(unc);
470*11963SAfshin.Ardakani@Sun.COM 		return (EINVAL);
471*11963SAfshin.Ardakani@Sun.COM 	}
472*11963SAfshin.Ardakani@Sun.COM 
473*11963SAfshin.Ardakani@Sun.COM 	unc->unc_path = strchr(unc->unc_share, '/');
474*11963SAfshin.Ardakani@Sun.COM 	if ((p = unc->unc_path) == NULL)
475*11963SAfshin.Ardakani@Sun.COM 		return (0);
476*11963SAfshin.Ardakani@Sun.COM 
477*11963SAfshin.Ardakani@Sun.COM 	unc->unc_path++;
478*11963SAfshin.Ardakani@Sun.COM 	*p = '\0';
479*11963SAfshin.Ardakani@Sun.COM 
480*11963SAfshin.Ardakani@Sun.COM 	/* remove the last '/' if any */
481*11963SAfshin.Ardakani@Sun.COM 	if ((p = strchr(unc->unc_path, '\0')) != NULL) {
482*11963SAfshin.Ardakani@Sun.COM 		if (*(--p) == '/')
483*11963SAfshin.Ardakani@Sun.COM 			*p = '\0';
484*11963SAfshin.Ardakani@Sun.COM 	}
485*11963SAfshin.Ardakani@Sun.COM 
486*11963SAfshin.Ardakani@Sun.COM 	return (0);
487*11963SAfshin.Ardakani@Sun.COM }
488*11963SAfshin.Ardakani@Sun.COM 
489*11963SAfshin.Ardakani@Sun.COM void
smb_unc_free(smb_unc_t * unc)490*11963SAfshin.Ardakani@Sun.COM smb_unc_free(smb_unc_t *unc)
491*11963SAfshin.Ardakani@Sun.COM {
492*11963SAfshin.Ardakani@Sun.COM 	if (unc == NULL)
493*11963SAfshin.Ardakani@Sun.COM 		return;
494*11963SAfshin.Ardakani@Sun.COM 
495*11963SAfshin.Ardakani@Sun.COM #ifdef _KERNEL
496*11963SAfshin.Ardakani@Sun.COM 	smb_mem_free(unc->unc_buf);
497*11963SAfshin.Ardakani@Sun.COM #else
498*11963SAfshin.Ardakani@Sun.COM 	free(unc->unc_buf);
499*11963SAfshin.Ardakani@Sun.COM #endif
500*11963SAfshin.Ardakani@Sun.COM 	unc->unc_buf = NULL;
501*11963SAfshin.Ardakani@Sun.COM }
502