diff options
Diffstat (limited to 'fs/cifs/cifs_unicode.c')
-rw-r--r-- | fs/cifs/cifs_unicode.c | 127 |
1 files changed, 104 insertions, 23 deletions
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 430f510a1720..fc0fd4fde306 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -44,10 +44,14 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
44 | int charlen, outlen = 0; | 44 | int charlen, outlen = 0; |
45 | int maxwords = maxbytes / 2; | 45 | int maxwords = maxbytes / 2; |
46 | char tmp[NLS_MAX_CHARSET_SIZE]; | 46 | char tmp[NLS_MAX_CHARSET_SIZE]; |
47 | __u16 ftmp; | ||
47 | 48 | ||
48 | for (i = 0; i < maxwords && from[i]; i++) { | 49 | for (i = 0; i < maxwords; i++) { |
49 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, | 50 | ftmp = get_unaligned_le16(&from[i]); |
50 | NLS_MAX_CHARSET_SIZE); | 51 | if (ftmp == 0) |
52 | break; | ||
53 | |||
54 | charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE); | ||
51 | if (charlen > 0) | 55 | if (charlen > 0) |
52 | outlen += charlen; | 56 | outlen += charlen; |
53 | else | 57 | else |
@@ -58,9 +62,9 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
58 | } | 62 | } |
59 | 63 | ||
60 | /* | 64 | /* |
61 | * cifs_mapchar - convert a little-endian char to proper char in codepage | 65 | * cifs_mapchar - convert a host-endian char to proper char in codepage |
62 | * @target - where converted character should be copied | 66 | * @target - where converted character should be copied |
63 | * @src_char - 2 byte little-endian source character | 67 | * @src_char - 2 byte host-endian source character |
64 | * @cp - codepage to which character should be converted | 68 | * @cp - codepage to which character should be converted |
65 | * @mapchar - should character be mapped according to mapchars mount option? | 69 | * @mapchar - should character be mapped according to mapchars mount option? |
66 | * | 70 | * |
@@ -69,7 +73,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
69 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | 73 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). |
70 | */ | 74 | */ |
71 | static int | 75 | static int |
72 | cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | 76 | cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, |
73 | bool mapchar) | 77 | bool mapchar) |
74 | { | 78 | { |
75 | int len = 1; | 79 | int len = 1; |
@@ -82,7 +86,7 @@ cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | |||
82 | * build_path_from_dentry are modified, as they use slash as | 86 | * build_path_from_dentry are modified, as they use slash as |
83 | * separator. | 87 | * separator. |
84 | */ | 88 | */ |
85 | switch (le16_to_cpu(src_char)) { | 89 | switch (src_char) { |
86 | case UNI_COLON: | 90 | case UNI_COLON: |
87 | *target = ':'; | 91 | *target = ':'; |
88 | break; | 92 | break; |
@@ -109,8 +113,7 @@ out: | |||
109 | return len; | 113 | return len; |
110 | 114 | ||
111 | cp_convert: | 115 | cp_convert: |
112 | len = cp->uni2char(le16_to_cpu(src_char), target, | 116 | len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); |
113 | NLS_MAX_CHARSET_SIZE); | ||
114 | if (len <= 0) { | 117 | if (len <= 0) { |
115 | *target = '?'; | 118 | *target = '?'; |
116 | len = 1; | 119 | len = 1; |
@@ -149,6 +152,7 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | |||
149 | int nullsize = nls_nullsize(codepage); | 152 | int nullsize = nls_nullsize(codepage); |
150 | int fromwords = fromlen / 2; | 153 | int fromwords = fromlen / 2; |
151 | char tmp[NLS_MAX_CHARSET_SIZE]; | 154 | char tmp[NLS_MAX_CHARSET_SIZE]; |
155 | __u16 ftmp; | ||
152 | 156 | ||
153 | /* | 157 | /* |
154 | * because the chars can be of varying widths, we need to take care | 158 | * because the chars can be of varying widths, we need to take care |
@@ -158,19 +162,23 @@ cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | |||
158 | */ | 162 | */ |
159 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | 163 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); |
160 | 164 | ||
161 | for (i = 0; i < fromwords && from[i]; i++) { | 165 | for (i = 0; i < fromwords; i++) { |
166 | ftmp = get_unaligned_le16(&from[i]); | ||
167 | if (ftmp == 0) | ||
168 | break; | ||
169 | |||
162 | /* | 170 | /* |
163 | * check to see if converting this character might make the | 171 | * check to see if converting this character might make the |
164 | * conversion bleed into the null terminator | 172 | * conversion bleed into the null terminator |
165 | */ | 173 | */ |
166 | if (outlen >= safelen) { | 174 | if (outlen >= safelen) { |
167 | charlen = cifs_mapchar(tmp, from[i], codepage, mapchar); | 175 | charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar); |
168 | if ((outlen + charlen) > (tolen - nullsize)) | 176 | if ((outlen + charlen) > (tolen - nullsize)) |
169 | break; | 177 | break; |
170 | } | 178 | } |
171 | 179 | ||
172 | /* put converted char into 'to' buffer */ | 180 | /* put converted char into 'to' buffer */ |
173 | charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar); | 181 | charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar); |
174 | outlen += charlen; | 182 | outlen += charlen; |
175 | } | 183 | } |
176 | 184 | ||
@@ -193,24 +201,21 @@ cifs_strtoUCS(__le16 *to, const char *from, int len, | |||
193 | { | 201 | { |
194 | int charlen; | 202 | int charlen; |
195 | int i; | 203 | int i; |
196 | wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */ | 204 | wchar_t wchar_to; /* needed to quiet sparse */ |
197 | 205 | ||
198 | for (i = 0; len && *from; i++, from += charlen, len -= charlen) { | 206 | for (i = 0; len && *from; i++, from += charlen, len -= charlen) { |
199 | 207 | charlen = codepage->char2uni(from, len, &wchar_to); | |
200 | /* works for 2.4.0 kernel or later */ | ||
201 | charlen = codepage->char2uni(from, len, &wchar_to[i]); | ||
202 | if (charlen < 1) { | 208 | if (charlen < 1) { |
203 | cERROR(1, "strtoUCS: char2uni of %d returned %d", | 209 | cERROR(1, "strtoUCS: char2uni of 0x%x returned %d", |
204 | (int)*from, charlen); | 210 | *from, charlen); |
205 | /* A question mark */ | 211 | /* A question mark */ |
206 | to[i] = cpu_to_le16(0x003f); | 212 | wchar_to = 0x003f; |
207 | charlen = 1; | 213 | charlen = 1; |
208 | } else | 214 | } |
209 | to[i] = cpu_to_le16(wchar_to[i]); | 215 | put_unaligned_le16(wchar_to, &to[i]); |
210 | |||
211 | } | 216 | } |
212 | 217 | ||
213 | to[i] = 0; | 218 | put_unaligned_le16(0, &to[i]); |
214 | return i; | 219 | return i; |
215 | } | 220 | } |
216 | 221 | ||
@@ -252,3 +257,79 @@ cifs_strndup_from_ucs(const char *src, const int maxlen, const bool is_unicode, | |||
252 | return dst; | 257 | return dst; |
253 | } | 258 | } |
254 | 259 | ||
260 | /* | ||
261 | * Convert 16 bit Unicode pathname to wire format from string in current code | ||
262 | * page. Conversion may involve remapping up the six characters that are | ||
263 | * only legal in POSIX-like OS (if they are present in the string). Path | ||
264 | * names are little endian 16 bit Unicode on the wire | ||
265 | */ | ||
266 | int | ||
267 | cifsConvertToUCS(__le16 *target, const char *source, int maxlen, | ||
268 | const struct nls_table *cp, int mapChars) | ||
269 | { | ||
270 | int i, j, charlen; | ||
271 | int len_remaining = maxlen; | ||
272 | char src_char; | ||
273 | __u16 temp; | ||
274 | |||
275 | if (!mapChars) | ||
276 | return cifs_strtoUCS(target, source, PATH_MAX, cp); | ||
277 | |||
278 | for (i = 0, j = 0; i < maxlen; j++) { | ||
279 | src_char = source[i]; | ||
280 | switch (src_char) { | ||
281 | case 0: | ||
282 | put_unaligned_le16(0, &target[j]); | ||
283 | goto ctoUCS_out; | ||
284 | case ':': | ||
285 | temp = UNI_COLON; | ||
286 | break; | ||
287 | case '*': | ||
288 | temp = UNI_ASTERIK; | ||
289 | break; | ||
290 | case '?': | ||
291 | temp = UNI_QUESTION; | ||
292 | break; | ||
293 | case '<': | ||
294 | temp = UNI_LESSTHAN; | ||
295 | break; | ||
296 | case '>': | ||
297 | temp = UNI_GRTRTHAN; | ||
298 | break; | ||
299 | case '|': | ||
300 | temp = UNI_PIPE; | ||
301 | break; | ||
302 | /* | ||
303 | * FIXME: We can not handle remapping backslash (UNI_SLASH) | ||
304 | * until all the calls to build_path_from_dentry are modified, | ||
305 | * as they use backslash as separator. | ||
306 | */ | ||
307 | default: | ||
308 | charlen = cp->char2uni(source+i, len_remaining, | ||
309 | &temp); | ||
310 | /* | ||
311 | * if no match, use question mark, which at least in | ||
312 | * some cases serves as wild card | ||
313 | */ | ||
314 | if (charlen < 1) { | ||
315 | temp = 0x003f; | ||
316 | charlen = 1; | ||
317 | } | ||
318 | len_remaining -= charlen; | ||
319 | /* | ||
320 | * character may take more than one byte in the source | ||
321 | * string, but will take exactly two bytes in the | ||
322 | * target string | ||
323 | */ | ||
324 | i += charlen; | ||
325 | continue; | ||
326 | } | ||
327 | put_unaligned_le16(temp, &target[j]); | ||
328 | i++; /* move to next char in source string */ | ||
329 | len_remaining--; | ||
330 | } | ||
331 | |||
332 | ctoUCS_out: | ||
333 | return i; | ||
334 | } | ||
335 | |||