Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * fs/cifs/cifs_unicode.c | |
3 | * | |
d185cda7 | 4 | * Copyright (c) International Business Machines Corp., 2000,2009 |
1da177e4 LT |
5 | * Modified by Steve French (sfrench@us.ibm.com) |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
221601c3 | 9 | * the Free Software Foundation; either version 2 of the License, or |
1da177e4 | 10 | * (at your option) any later version. |
221601c3 | 11 | * |
1da177e4 LT |
12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
15 | * the GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
221601c3 | 18 | * along with this program; if not, write to the Free Software |
1da177e4 LT |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | |
21 | #include <linux/fs.h> | |
5a0e3ad6 | 22 | #include <linux/slab.h> |
1da177e4 LT |
23 | #include "cifs_unicode.h" |
24 | #include "cifs_uniupr.h" | |
25 | #include "cifspdu.h" | |
3979877e | 26 | #include "cifsglob.h" |
1da177e4 LT |
27 | #include "cifs_debug.h" |
28 | ||
69f801fc JL |
29 | /* |
30 | * cifs_ucs2_bytes - how long will a string be after conversion? | |
31 | * @ucs - pointer to input string | |
32 | * @maxbytes - don't go past this many bytes of input string | |
33 | * @codepage - destination codepage | |
34 | * | |
35 | * Walk a ucs2le string and return the number of bytes that the string will | |
36 | * be after being converted to the given charset, not including any null | |
37 | * termination required. Don't walk past maxbytes in the source buffer. | |
38 | */ | |
39 | int | |
40 | cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |
41 | const struct nls_table *codepage) | |
42 | { | |
43 | int i; | |
44 | int charlen, outlen = 0; | |
45 | int maxwords = maxbytes / 2; | |
46 | char tmp[NLS_MAX_CHARSET_SIZE]; | |
47 | ||
24e2fb61 | 48 | for (i = 0; i < maxwords && from[i]; i++) { |
69f801fc JL |
49 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, |
50 | NLS_MAX_CHARSET_SIZE); | |
51 | if (charlen > 0) | |
52 | outlen += charlen; | |
53 | else | |
54 | outlen++; | |
55 | } | |
56 | ||
57 | return outlen; | |
58 | } | |
59 | ||
7fabf0c9 JL |
60 | /* |
61 | * cifs_mapchar - convert a little-endian char to proper char in codepage | |
62 | * @target - where converted character should be copied | |
63 | * @src_char - 2 byte little-endian source character | |
64 | * @cp - codepage to which character should be converted | |
65 | * @mapchar - should character be mapped according to mapchars mount option? | |
66 | * | |
67 | * This function handles the conversion of a single character. It is the | |
68 | * responsibility of the caller to ensure that the target buffer is large | |
69 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | |
70 | */ | |
71 | static int | |
72 | cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | |
73 | bool mapchar) | |
74 | { | |
75 | int len = 1; | |
76 | ||
77 | if (!mapchar) | |
78 | goto cp_convert; | |
79 | ||
80 | /* | |
81 | * BB: Cannot handle remapping UNI_SLASH until all the calls to | |
82 | * build_path_from_dentry are modified, as they use slash as | |
83 | * separator. | |
84 | */ | |
85 | switch (le16_to_cpu(src_char)) { | |
86 | case UNI_COLON: | |
87 | *target = ':'; | |
88 | break; | |
89 | case UNI_ASTERIK: | |
90 | *target = '*'; | |
91 | break; | |
92 | case UNI_QUESTION: | |
93 | *target = '?'; | |
94 | break; | |
95 | case UNI_PIPE: | |
96 | *target = '|'; | |
97 | break; | |
98 | case UNI_GRTRTHAN: | |
99 | *target = '>'; | |
100 | break; | |
101 | case UNI_LESSTHAN: | |
102 | *target = '<'; | |
103 | break; | |
104 | default: | |
105 | goto cp_convert; | |
106 | } | |
107 | ||
108 | out: | |
109 | return len; | |
110 | ||
111 | cp_convert: | |
112 | len = cp->uni2char(le16_to_cpu(src_char), target, | |
113 | NLS_MAX_CHARSET_SIZE); | |
114 | if (len <= 0) { | |
115 | *target = '?'; | |
116 | len = 1; | |
117 | } | |
118 | goto out; | |
119 | } | |
120 | ||
121 | /* | |
122 | * cifs_from_ucs2 - convert utf16le string to local charset | |
123 | * @to - destination buffer | |
124 | * @from - source buffer | |
125 | * @tolen - destination buffer size (in bytes) | |
126 | * @fromlen - source buffer size (in bytes) | |
127 | * @codepage - codepage to which characters should be converted | |
128 | * @mapchar - should characters be remapped according to the mapchars option? | |
129 | * | |
130 | * Convert a little-endian ucs2le string (as sent by the server) to a string | |
131 | * in the provided codepage. The tolen and fromlen parameters are to ensure | |
132 | * that the code doesn't walk off of the end of the buffer (which is always | |
133 | * a danger if the alignment of the source buffer is off). The destination | |
134 | * string is always properly null terminated and fits in the destination | |
135 | * buffer. Returns the length of the destination string in bytes (including | |
136 | * null terminator). | |
137 | * | |
138 | * Note that some windows versions actually send multiword UTF-16 characters | |
139 | * instead of straight UCS-2. The linux nls routines however aren't able to | |
140 | * deal with those characters properly. In the event that we get some of | |
141 | * those characters, they won't be translated properly. | |
142 | */ | |
143 | int | |
144 | cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | |
145 | const struct nls_table *codepage, bool mapchar) | |
146 | { | |
147 | int i, charlen, safelen; | |
148 | int outlen = 0; | |
149 | int nullsize = nls_nullsize(codepage); | |
150 | int fromwords = fromlen / 2; | |
151 | char tmp[NLS_MAX_CHARSET_SIZE]; | |
152 | ||
153 | /* | |
154 | * because the chars can be of varying widths, we need to take care | |
155 | * not to overflow the destination buffer when we get close to the | |
156 | * end of it. Until we get to this offset, we don't need to check | |
157 | * for overflow however. | |
158 | */ | |
159 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | |
160 | ||
161 | for (i = 0; i < fromwords && from[i]; i++) { | |
162 | /* | |
163 | * check to see if converting this character might make the | |
164 | * conversion bleed into the null terminator | |
165 | */ | |
166 | if (outlen >= safelen) { | |
167 | charlen = cifs_mapchar(tmp, from[i], codepage, mapchar); | |
168 | if ((outlen + charlen) > (tolen - nullsize)) | |
169 | break; | |
170 | } | |
171 | ||
172 | /* put converted char into 'to' buffer */ | |
173 | charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar); | |
174 | outlen += charlen; | |
175 | } | |
176 | ||
177 | /* properly null-terminate string */ | |
178 | for (i = 0; i < nullsize; i++) | |
179 | to[outlen++] = 0; | |
180 | ||
181 | return outlen; | |
182 | } | |
183 | ||
1da177e4 LT |
184 | /* |
185 | * NAME: cifs_strtoUCS() | |
186 | * | |
187 | * FUNCTION: Convert character string to unicode string | |
188 | * | |
189 | */ | |
190 | int | |
ad7a2926 | 191 | cifs_strtoUCS(__le16 *to, const char *from, int len, |
1da177e4 LT |
192 | const struct nls_table *codepage) |
193 | { | |
194 | int charlen; | |
195 | int i; | |
50c2f753 | 196 | wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */ |
1da177e4 LT |
197 | |
198 | for (i = 0; len && *from; i++, from += charlen, len -= charlen) { | |
199 | ||
200 | /* works for 2.4.0 kernel or later */ | |
e89dc920 | 201 | charlen = codepage->char2uni(from, len, &wchar_to[i]); |
1da177e4 LT |
202 | if (charlen < 1) { |
203 | cERROR(1, | |
3a9f462f SF |
204 | ("strtoUCS: char2uni of %d returned %d", |
205 | (int)*from, charlen)); | |
69114089 | 206 | /* A question mark */ |
e89dc920 | 207 | to[i] = cpu_to_le16(0x003f); |
1da177e4 | 208 | charlen = 1; |
221601c3 | 209 | } else |
e89dc920 | 210 | to[i] = cpu_to_le16(wchar_to[i]); |
1da177e4 LT |
211 | |
212 | } | |
213 | ||
214 | to[i] = 0; | |
215 | return i; | |
216 | } | |
217 | ||
066ce689 | 218 | /* |
d185cda7 | 219 | * cifs_strndup_from_ucs - copy a string from wire format to the local codepage |
066ce689 JL |
220 | * @src - source string |
221 | * @maxlen - don't walk past this many bytes in the source string | |
222 | * @is_unicode - is this a unicode string? | |
223 | * @codepage - destination codepage | |
224 | * | |
225 | * Take a string given by the server, convert it to the local codepage and | |
226 | * put it in a new buffer. Returns a pointer to the new string or NULL on | |
227 | * error. | |
228 | */ | |
229 | char * | |
d185cda7 | 230 | cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, |
066ce689 JL |
231 | const struct nls_table *codepage) |
232 | { | |
233 | int len; | |
234 | char *dst; | |
235 | ||
236 | if (is_unicode) { | |
237 | len = cifs_ucs2_bytes((__le16 *) src, maxlen, codepage); | |
238 | len += nls_nullsize(codepage); | |
239 | dst = kmalloc(len, GFP_KERNEL); | |
240 | if (!dst) | |
241 | return NULL; | |
242 | cifs_from_ucs2(dst, (__le16 *) src, len, maxlen, codepage, | |
243 | false); | |
244 | } else { | |
245 | len = strnlen(src, maxlen); | |
246 | len++; | |
247 | dst = kmalloc(len, GFP_KERNEL); | |
248 | if (!dst) | |
249 | return NULL; | |
250 | strlcpy(dst, src, len); | |
251 | } | |
252 | ||
253 | return dst; | |
254 | } | |
255 |