1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include <linux/fs.h>
22#include <linux/slab.h>
23#include "cifs_unicode.h"
24#include "cifs_uniupr.h"
25#include "cifspdu.h"
26#include "cifsglob.h"
27#include "cifs_debug.h"
28
29
30
31
32
33
34
35
36
37
38
39int
40cifs_utf16_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 __u16 ftmp;
48
49 for (i = 0; i < maxwords; i++) {
50 ftmp = get_unaligned_le16(&from[i]);
51 if (ftmp == 0)
52 break;
53
54 charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
55 if (charlen > 0)
56 outlen += charlen;
57 else
58 outlen++;
59 }
60
61 return outlen;
62}
63
64
65
66
67
68
69
70
71
72
73
74
75static int
76cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
77 bool mapchar)
78{
79 int len = 1;
80
81 if (!mapchar)
82 goto cp_convert;
83
84
85
86
87
88
89 switch (src_char) {
90 case UNI_COLON:
91 *target = ':';
92 break;
93 case UNI_ASTERISK:
94 *target = '*';
95 break;
96 case UNI_QUESTION:
97 *target = '?';
98 break;
99 case UNI_PIPE:
100 *target = '|';
101 break;
102 case UNI_GRTRTHAN:
103 *target = '>';
104 break;
105 case UNI_LESSTHAN:
106 *target = '<';
107 break;
108 default:
109 goto cp_convert;
110 }
111
112out:
113 return len;
114
115cp_convert:
116 len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
117 if (len <= 0) {
118 *target = '?';
119 len = 1;
120 }
121 goto out;
122}
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146int
147cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
148 const struct nls_table *codepage, bool mapchar)
149{
150 int i, charlen, safelen;
151 int outlen = 0;
152 int nullsize = nls_nullsize(codepage);
153 int fromwords = fromlen / 2;
154 char tmp[NLS_MAX_CHARSET_SIZE];
155 __u16 ftmp;
156
157
158
159
160
161
162
163 safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
164
165 for (i = 0; i < fromwords; i++) {
166 ftmp = get_unaligned_le16(&from[i]);
167 if (ftmp == 0)
168 break;
169
170
171
172
173
174 if (outlen >= safelen) {
175 charlen = cifs_mapchar(tmp, ftmp, codepage, mapchar);
176 if ((outlen + charlen) > (tolen - nullsize))
177 break;
178 }
179
180
181 charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
182 outlen += charlen;
183 }
184
185
186 for (i = 0; i < nullsize; i++)
187 to[outlen++] = 0;
188
189 return outlen;
190}
191
192
193
194
195
196
197
198int
199cifs_strtoUTF16(__le16 *to, const char *from, int len,
200 const struct nls_table *codepage)
201{
202 int charlen;
203 int i;
204 wchar_t wchar_to;
205
206
207 if (!strcmp(codepage->charset, "utf8")) {
208
209
210
211
212
213 i = utf8s_to_utf16s(from, len, UTF16_LITTLE_ENDIAN,
214 (wchar_t *) to, len);
215
216
217 if (i >= 0)
218 goto success;
219
220
221
222
223
224
225 }
226
227 for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
228 charlen = codepage->char2uni(from, len, &wchar_to);
229 if (charlen < 1) {
230 cifs_dbg(VFS, "strtoUTF16: char2uni of 0x%x returned %d\n",
231 *from, charlen);
232
233 wchar_to = 0x003f;
234 charlen = 1;
235 }
236 put_unaligned_le16(wchar_to, &to[i]);
237 }
238
239success:
240 put_unaligned_le16(0, &to[i]);
241 return i;
242}
243
244
245
246
247
248
249
250
251
252
253
254
255
256char *
257cifs_strndup_from_utf16(const char *src, const int maxlen,
258 const bool is_unicode, const struct nls_table *codepage)
259{
260 int len;
261 char *dst;
262
263 if (is_unicode) {
264 len = cifs_utf16_bytes((__le16 *) src, maxlen, codepage);
265 len += nls_nullsize(codepage);
266 dst = kmalloc(len, GFP_KERNEL);
267 if (!dst)
268 return NULL;
269 cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage,
270 false);
271 } else {
272 len = strnlen(src, maxlen);
273 len++;
274 dst = kmalloc(len, GFP_KERNEL);
275 if (!dst)
276 return NULL;
277 strlcpy(dst, src, len);
278 }
279
280 return dst;
281}
282
283
284
285
286
287
288
289int
290cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
291 const struct nls_table *cp, int mapChars)
292{
293 int i, j, charlen;
294 char src_char;
295 __le16 dst_char;
296 wchar_t tmp;
297
298 if (!mapChars)
299 return cifs_strtoUTF16(target, source, PATH_MAX, cp);
300
301 for (i = 0, j = 0; i < srclen; j++) {
302 src_char = source[i];
303 charlen = 1;
304 switch (src_char) {
305 case 0:
306 put_unaligned(0, &target[j]);
307 goto ctoUTF16_out;
308 case ':':
309 dst_char = cpu_to_le16(UNI_COLON);
310 break;
311 case '*':
312 dst_char = cpu_to_le16(UNI_ASTERISK);
313 break;
314 case '?':
315 dst_char = cpu_to_le16(UNI_QUESTION);
316 break;
317 case '<':
318 dst_char = cpu_to_le16(UNI_LESSTHAN);
319 break;
320 case '>':
321 dst_char = cpu_to_le16(UNI_GRTRTHAN);
322 break;
323 case '|':
324 dst_char = cpu_to_le16(UNI_PIPE);
325 break;
326
327
328
329
330
331 default:
332 charlen = cp->char2uni(source + i, srclen - i, &tmp);
333 dst_char = cpu_to_le16(tmp);
334
335
336
337
338
339 if (charlen < 1) {
340 dst_char = cpu_to_le16(0x003f);
341 charlen = 1;
342 }
343 }
344
345
346
347
348 i += charlen;
349 put_unaligned(dst_char, &target[j]);
350 }
351
352ctoUTF16_out:
353 return j;
354}
355
356#ifdef CONFIG_CIFS_SMB2
357
358
359
360
361
362
363
364
365
366
367
368static int
369cifs_local_to_utf16_bytes(const char *from, int len,
370 const struct nls_table *codepage)
371{
372 int charlen;
373 int i;
374 wchar_t wchar_to;
375
376 for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
377 charlen = codepage->char2uni(from, len, &wchar_to);
378
379 if (charlen < 1)
380 charlen = 1;
381 }
382 return 2 * i;
383}
384
385
386
387
388
389
390
391
392
393
394
395
396
397__le16 *
398cifs_strndup_to_utf16(const char *src, const int maxlen, int *utf16_len,
399 const struct nls_table *cp, int remap)
400{
401 int len;
402 __le16 *dst;
403
404 len = cifs_local_to_utf16_bytes(src, maxlen, cp);
405 len += 2;
406 dst = kmalloc(len, GFP_KERNEL);
407 if (!dst) {
408 *utf16_len = 0;
409 return NULL;
410 }
411 cifsConvertToUTF16(dst, src, strlen(src), cp, remap);
412 *utf16_len = len;
413 return dst;
414}
415#endif
416