diff options
-rw-r--r-- | include/linux/string_helpers.h | 31 | ||||
-rw-r--r-- | lib/string_helpers.c | 274 | ||||
-rw-r--r-- | lib/test-string_helpers.c | 240 |
3 files changed, 541 insertions, 4 deletions
diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h index 5a30f2a86239..6eb567ac56bc 100644 --- a/include/linux/string_helpers.h +++ b/include/linux/string_helpers.h | |||
@@ -37,4 +37,35 @@ static inline int string_unescape_any_inplace(char *buf) | |||
37 | return string_unescape_any(buf, buf, 0); | 37 | return string_unescape_any(buf, buf, 0); |
38 | } | 38 | } |
39 | 39 | ||
40 | #define ESCAPE_SPACE 0x01 | ||
41 | #define ESCAPE_SPECIAL 0x02 | ||
42 | #define ESCAPE_NULL 0x04 | ||
43 | #define ESCAPE_OCTAL 0x08 | ||
44 | #define ESCAPE_ANY \ | ||
45 | (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL) | ||
46 | #define ESCAPE_NP 0x10 | ||
47 | #define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP) | ||
48 | #define ESCAPE_HEX 0x20 | ||
49 | |||
50 | int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, | ||
51 | unsigned int flags, const char *esc); | ||
52 | |||
53 | static inline int string_escape_mem_any_np(const char *src, size_t isz, | ||
54 | char **dst, size_t osz, const char *esc) | ||
55 | { | ||
56 | return string_escape_mem(src, isz, dst, osz, ESCAPE_ANY_NP, esc); | ||
57 | } | ||
58 | |||
59 | static inline int string_escape_str(const char *src, char **dst, size_t sz, | ||
60 | unsigned int flags, const char *esc) | ||
61 | { | ||
62 | return string_escape_mem(src, strlen(src), dst, sz, flags, esc); | ||
63 | } | ||
64 | |||
65 | static inline int string_escape_str_any_np(const char *src, char **dst, | ||
66 | size_t sz, const char *esc) | ||
67 | { | ||
68 | return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, esc); | ||
69 | } | ||
70 | |||
40 | #endif | 71 | #endif |
diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 74ec60469640..58b78ba57439 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <linux/math64.h> | 8 | #include <linux/math64.h> |
9 | #include <linux/export.h> | 9 | #include <linux/export.h> |
10 | #include <linux/ctype.h> | 10 | #include <linux/ctype.h> |
11 | #include <linux/errno.h> | ||
12 | #include <linux/string.h> | ||
11 | #include <linux/string_helpers.h> | 13 | #include <linux/string_helpers.h> |
12 | 14 | ||
13 | /** | 15 | /** |
@@ -240,3 +242,275 @@ int string_unescape(char *src, char *dst, size_t size, unsigned int flags) | |||
240 | return out - dst; | 242 | return out - dst; |
241 | } | 243 | } |
242 | EXPORT_SYMBOL(string_unescape); | 244 | EXPORT_SYMBOL(string_unescape); |
245 | |||
246 | static int escape_passthrough(unsigned char c, char **dst, size_t *osz) | ||
247 | { | ||
248 | char *out = *dst; | ||
249 | |||
250 | if (*osz < 1) | ||
251 | return -ENOMEM; | ||
252 | |||
253 | *out++ = c; | ||
254 | |||
255 | *dst = out; | ||
256 | *osz -= 1; | ||
257 | |||
258 | return 1; | ||
259 | } | ||
260 | |||
261 | static int escape_space(unsigned char c, char **dst, size_t *osz) | ||
262 | { | ||
263 | char *out = *dst; | ||
264 | unsigned char to; | ||
265 | |||
266 | if (*osz < 2) | ||
267 | return -ENOMEM; | ||
268 | |||
269 | switch (c) { | ||
270 | case '\n': | ||
271 | to = 'n'; | ||
272 | break; | ||
273 | case '\r': | ||
274 | to = 'r'; | ||
275 | break; | ||
276 | case '\t': | ||
277 | to = 't'; | ||
278 | break; | ||
279 | case '\v': | ||
280 | to = 'v'; | ||
281 | break; | ||
282 | case '\f': | ||
283 | to = 'f'; | ||
284 | break; | ||
285 | default: | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | *out++ = '\\'; | ||
290 | *out++ = to; | ||
291 | |||
292 | *dst = out; | ||
293 | *osz -= 2; | ||
294 | |||
295 | return 1; | ||
296 | } | ||
297 | |||
298 | static int escape_special(unsigned char c, char **dst, size_t *osz) | ||
299 | { | ||
300 | char *out = *dst; | ||
301 | unsigned char to; | ||
302 | |||
303 | if (*osz < 2) | ||
304 | return -ENOMEM; | ||
305 | |||
306 | switch (c) { | ||
307 | case '\\': | ||
308 | to = '\\'; | ||
309 | break; | ||
310 | case '\a': | ||
311 | to = 'a'; | ||
312 | break; | ||
313 | case '\e': | ||
314 | to = 'e'; | ||
315 | break; | ||
316 | default: | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | *out++ = '\\'; | ||
321 | *out++ = to; | ||
322 | |||
323 | *dst = out; | ||
324 | *osz -= 2; | ||
325 | |||
326 | return 1; | ||
327 | } | ||
328 | |||
329 | static int escape_null(unsigned char c, char **dst, size_t *osz) | ||
330 | { | ||
331 | char *out = *dst; | ||
332 | |||
333 | if (*osz < 2) | ||
334 | return -ENOMEM; | ||
335 | |||
336 | if (c) | ||
337 | return 0; | ||
338 | |||
339 | *out++ = '\\'; | ||
340 | *out++ = '0'; | ||
341 | |||
342 | *dst = out; | ||
343 | *osz -= 2; | ||
344 | |||
345 | return 1; | ||
346 | } | ||
347 | |||
348 | static int escape_octal(unsigned char c, char **dst, size_t *osz) | ||
349 | { | ||
350 | char *out = *dst; | ||
351 | |||
352 | if (*osz < 4) | ||
353 | return -ENOMEM; | ||
354 | |||
355 | *out++ = '\\'; | ||
356 | *out++ = ((c >> 6) & 0x07) + '0'; | ||
357 | *out++ = ((c >> 3) & 0x07) + '0'; | ||
358 | *out++ = ((c >> 0) & 0x07) + '0'; | ||
359 | |||
360 | *dst = out; | ||
361 | *osz -= 4; | ||
362 | |||
363 | return 1; | ||
364 | } | ||
365 | |||
366 | static int escape_hex(unsigned char c, char **dst, size_t *osz) | ||
367 | { | ||
368 | char *out = *dst; | ||
369 | |||
370 | if (*osz < 4) | ||
371 | return -ENOMEM; | ||
372 | |||
373 | *out++ = '\\'; | ||
374 | *out++ = 'x'; | ||
375 | *out++ = hex_asc_hi(c); | ||
376 | *out++ = hex_asc_lo(c); | ||
377 | |||
378 | *dst = out; | ||
379 | *osz -= 4; | ||
380 | |||
381 | return 1; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * string_escape_mem - quote characters in the given memory buffer | ||
386 | * @src: source buffer (unescaped) | ||
387 | * @isz: source buffer size | ||
388 | * @dst: destination buffer (escaped) | ||
389 | * @osz: destination buffer size | ||
390 | * @flags: combination of the flags (bitwise OR): | ||
391 | * %ESCAPE_SPACE: | ||
392 | * '\f' - form feed | ||
393 | * '\n' - new line | ||
394 | * '\r' - carriage return | ||
395 | * '\t' - horizontal tab | ||
396 | * '\v' - vertical tab | ||
397 | * %ESCAPE_SPECIAL: | ||
398 | * '\\' - backslash | ||
399 | * '\a' - alert (BEL) | ||
400 | * '\e' - escape | ||
401 | * %ESCAPE_NULL: | ||
402 | * '\0' - null | ||
403 | * %ESCAPE_OCTAL: | ||
404 | * '\NNN' - byte with octal value NNN (3 digits) | ||
405 | * %ESCAPE_ANY: | ||
406 | * all previous together | ||
407 | * %ESCAPE_NP: | ||
408 | * escape only non-printable characters (checked by isprint) | ||
409 | * %ESCAPE_ANY_NP: | ||
410 | * all previous together | ||
411 | * %ESCAPE_HEX: | ||
412 | * '\xHH' - byte with hexadecimal value HH (2 digits) | ||
413 | * @esc: NULL-terminated string of characters any of which, if found in | ||
414 | * the source, has to be escaped | ||
415 | * | ||
416 | * Description: | ||
417 | * The process of escaping byte buffer includes several parts. They are applied | ||
418 | * in the following sequence. | ||
419 | * 1. The character is matched to the printable class, if asked, and in | ||
420 | * case of match it passes through to the output. | ||
421 | * 2. The character is not matched to the one from @esc string and thus | ||
422 | * must go as is to the output. | ||
423 | * 3. The character is checked if it falls into the class given by @flags. | ||
424 | * %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any | ||
425 | * character. Note that they actually can't go together, otherwise | ||
426 | * %ESCAPE_HEX will be ignored. | ||
427 | * | ||
428 | * Caller must provide valid source and destination pointers. Be aware that | ||
429 | * destination buffer will not be NULL-terminated, thus caller have to append | ||
430 | * it if needs. | ||
431 | * | ||
432 | * Return: | ||
433 | * The amount of the characters processed to the destination buffer, or | ||
434 | * %-ENOMEM if the size of buffer is not enough to put an escaped character is | ||
435 | * returned. | ||
436 | * | ||
437 | * Even in the case of error @dst pointer will be updated to point to the byte | ||
438 | * after the last processed character. | ||
439 | */ | ||
440 | int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, | ||
441 | unsigned int flags, const char *esc) | ||
442 | { | ||
443 | char *out = *dst, *p = out; | ||
444 | bool is_dict = esc && *esc; | ||
445 | int ret = 0; | ||
446 | |||
447 | while (isz--) { | ||
448 | unsigned char c = *src++; | ||
449 | |||
450 | /* | ||
451 | * Apply rules in the following sequence: | ||
452 | * - the character is printable, when @flags has | ||
453 | * %ESCAPE_NP bit set | ||
454 | * - the @esc string is supplied and does not contain a | ||
455 | * character under question | ||
456 | * - the character doesn't fall into a class of symbols | ||
457 | * defined by given @flags | ||
458 | * In these cases we just pass through a character to the | ||
459 | * output buffer. | ||
460 | */ | ||
461 | if ((flags & ESCAPE_NP && isprint(c)) || | ||
462 | (is_dict && !strchr(esc, c))) { | ||
463 | /* do nothing */ | ||
464 | } else { | ||
465 | if (flags & ESCAPE_SPACE) { | ||
466 | ret = escape_space(c, &p, &osz); | ||
467 | if (ret < 0) | ||
468 | break; | ||
469 | if (ret > 0) | ||
470 | continue; | ||
471 | } | ||
472 | |||
473 | if (flags & ESCAPE_SPECIAL) { | ||
474 | ret = escape_special(c, &p, &osz); | ||
475 | if (ret < 0) | ||
476 | break; | ||
477 | if (ret > 0) | ||
478 | continue; | ||
479 | } | ||
480 | |||
481 | if (flags & ESCAPE_NULL) { | ||
482 | ret = escape_null(c, &p, &osz); | ||
483 | if (ret < 0) | ||
484 | break; | ||
485 | if (ret > 0) | ||
486 | continue; | ||
487 | } | ||
488 | |||
489 | /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ | ||
490 | if (flags & ESCAPE_OCTAL) { | ||
491 | ret = escape_octal(c, &p, &osz); | ||
492 | if (ret < 0) | ||
493 | break; | ||
494 | continue; | ||
495 | } | ||
496 | if (flags & ESCAPE_HEX) { | ||
497 | ret = escape_hex(c, &p, &osz); | ||
498 | if (ret < 0) | ||
499 | break; | ||
500 | continue; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | ret = escape_passthrough(c, &p, &osz); | ||
505 | if (ret < 0) | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | *dst = p; | ||
510 | |||
511 | if (ret < 0) | ||
512 | return ret; | ||
513 | |||
514 | return p - out; | ||
515 | } | ||
516 | EXPORT_SYMBOL(string_escape_mem); | ||
diff --git a/lib/test-string_helpers.c b/lib/test-string_helpers.c index ac44c9245dcf..ab0d30e1e18f 100644 --- a/lib/test-string_helpers.c +++ b/lib/test-string_helpers.c | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
8 | #include <linux/slab.h> | ||
8 | #include <linux/module.h> | 9 | #include <linux/module.h> |
9 | #include <linux/random.h> | 10 | #include <linux/random.h> |
10 | #include <linux/string.h> | 11 | #include <linux/string.h> |
@@ -62,10 +63,14 @@ static const struct test_string strings[] __initconst = { | |||
62 | static void __init test_string_unescape(const char *name, unsigned int flags, | 63 | static void __init test_string_unescape(const char *name, unsigned int flags, |
63 | bool inplace) | 64 | bool inplace) |
64 | { | 65 | { |
65 | char in[256]; | 66 | int q_real = 256; |
66 | char out_test[256]; | 67 | char *in = kmalloc(q_real, GFP_KERNEL); |
67 | char out_real[256]; | 68 | char *out_test = kmalloc(q_real, GFP_KERNEL); |
68 | int i, p = 0, q_test = 0, q_real = sizeof(out_real); | 69 | char *out_real = kmalloc(q_real, GFP_KERNEL); |
70 | int i, p = 0, q_test = 0; | ||
71 | |||
72 | if (!in || !out_test || !out_real) | ||
73 | goto out; | ||
69 | 74 | ||
70 | for (i = 0; i < ARRAY_SIZE(strings); i++) { | 75 | for (i = 0; i < ARRAY_SIZE(strings); i++) { |
71 | const char *s = strings[i].in; | 76 | const char *s = strings[i].in; |
@@ -100,6 +105,223 @@ static void __init test_string_unescape(const char *name, unsigned int flags, | |||
100 | 105 | ||
101 | test_string_check_buf(name, flags, in, p - 1, out_real, q_real, | 106 | test_string_check_buf(name, flags, in, p - 1, out_real, q_real, |
102 | out_test, q_test); | 107 | out_test, q_test); |
108 | out: | ||
109 | kfree(out_real); | ||
110 | kfree(out_test); | ||
111 | kfree(in); | ||
112 | } | ||
113 | |||
114 | struct test_string_1 { | ||
115 | const char *out; | ||
116 | unsigned int flags; | ||
117 | }; | ||
118 | |||
119 | #define TEST_STRING_2_MAX_S1 32 | ||
120 | struct test_string_2 { | ||
121 | const char *in; | ||
122 | struct test_string_1 s1[TEST_STRING_2_MAX_S1]; | ||
123 | }; | ||
124 | |||
125 | #define TEST_STRING_2_DICT_0 NULL | ||
126 | static const struct test_string_2 escape0[] __initconst = {{ | ||
127 | .in = "\f\\ \n\r\t\v", | ||
128 | .s1 = {{ | ||
129 | .out = "\\f\\ \\n\\r\\t\\v", | ||
130 | .flags = ESCAPE_SPACE, | ||
131 | },{ | ||
132 | .out = "\\f\\134\\040\\n\\r\\t\\v", | ||
133 | .flags = ESCAPE_SPACE | ESCAPE_OCTAL, | ||
134 | },{ | ||
135 | .out = "\\f\\x5c\\x20\\n\\r\\t\\v", | ||
136 | .flags = ESCAPE_SPACE | ESCAPE_HEX, | ||
137 | },{ | ||
138 | /* terminator */ | ||
139 | }}, | ||
140 | },{ | ||
141 | .in = "\\h\\\"\a\e\\", | ||
142 | .s1 = {{ | ||
143 | .out = "\\\\h\\\\\"\\a\\e\\\\", | ||
144 | .flags = ESCAPE_SPECIAL, | ||
145 | },{ | ||
146 | .out = "\\\\\\150\\\\\\042\\a\\e\\\\", | ||
147 | .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL, | ||
148 | },{ | ||
149 | .out = "\\\\\\x68\\\\\\x22\\a\\e\\\\", | ||
150 | .flags = ESCAPE_SPECIAL | ESCAPE_HEX, | ||
151 | },{ | ||
152 | /* terminator */ | ||
153 | }}, | ||
154 | },{ | ||
155 | .in = "\eb \\C\007\"\x90\r]", | ||
156 | .s1 = {{ | ||
157 | .out = "\eb \\C\007\"\x90\\r]", | ||
158 | .flags = ESCAPE_SPACE, | ||
159 | },{ | ||
160 | .out = "\\eb \\\\C\\a\"\x90\r]", | ||
161 | .flags = ESCAPE_SPECIAL, | ||
162 | },{ | ||
163 | .out = "\\eb \\\\C\\a\"\x90\\r]", | ||
164 | .flags = ESCAPE_SPACE | ESCAPE_SPECIAL, | ||
165 | },{ | ||
166 | .out = "\\033\\142\\040\\134\\103\\007\\042\\220\\015\\135", | ||
167 | .flags = ESCAPE_OCTAL, | ||
168 | },{ | ||
169 | .out = "\\033\\142\\040\\134\\103\\007\\042\\220\\r\\135", | ||
170 | .flags = ESCAPE_SPACE | ESCAPE_OCTAL, | ||
171 | },{ | ||
172 | .out = "\\e\\142\\040\\\\\\103\\a\\042\\220\\015\\135", | ||
173 | .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL, | ||
174 | },{ | ||
175 | .out = "\\e\\142\\040\\\\\\103\\a\\042\\220\\r\\135", | ||
176 | .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_OCTAL, | ||
177 | },{ | ||
178 | .out = "\eb \\C\007\"\x90\r]", | ||
179 | .flags = ESCAPE_NP, | ||
180 | },{ | ||
181 | .out = "\eb \\C\007\"\x90\\r]", | ||
182 | .flags = ESCAPE_SPACE | ESCAPE_NP, | ||
183 | },{ | ||
184 | .out = "\\eb \\C\\a\"\x90\r]", | ||
185 | .flags = ESCAPE_SPECIAL | ESCAPE_NP, | ||
186 | },{ | ||
187 | .out = "\\eb \\C\\a\"\x90\\r]", | ||
188 | .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_NP, | ||
189 | },{ | ||
190 | .out = "\\033b \\C\\007\"\\220\\015]", | ||
191 | .flags = ESCAPE_OCTAL | ESCAPE_NP, | ||
192 | },{ | ||
193 | .out = "\\033b \\C\\007\"\\220\\r]", | ||
194 | .flags = ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_NP, | ||
195 | },{ | ||
196 | .out = "\\eb \\C\\a\"\\220\\r]", | ||
197 | .flags = ESCAPE_SPECIAL | ESCAPE_SPACE | ESCAPE_OCTAL | | ||
198 | ESCAPE_NP, | ||
199 | },{ | ||
200 | .out = "\\x1bb \\C\\x07\"\\x90\\x0d]", | ||
201 | .flags = ESCAPE_NP | ESCAPE_HEX, | ||
202 | },{ | ||
203 | /* terminator */ | ||
204 | }}, | ||
205 | },{ | ||
206 | /* terminator */ | ||
207 | }}; | ||
208 | |||
209 | #define TEST_STRING_2_DICT_1 "b\\ \t\r" | ||
210 | static const struct test_string_2 escape1[] __initconst = {{ | ||
211 | .in = "\f\\ \n\r\t\v", | ||
212 | .s1 = {{ | ||
213 | .out = "\f\\134\\040\n\\015\\011\v", | ||
214 | .flags = ESCAPE_OCTAL, | ||
215 | },{ | ||
216 | .out = "\f\\x5c\\x20\n\\x0d\\x09\v", | ||
217 | .flags = ESCAPE_HEX, | ||
218 | },{ | ||
219 | /* terminator */ | ||
220 | }}, | ||
221 | },{ | ||
222 | .in = "\\h\\\"\a\e\\", | ||
223 | .s1 = {{ | ||
224 | .out = "\\134h\\134\"\a\e\\134", | ||
225 | .flags = ESCAPE_OCTAL, | ||
226 | },{ | ||
227 | /* terminator */ | ||
228 | }}, | ||
229 | },{ | ||
230 | .in = "\eb \\C\007\"\x90\r]", | ||
231 | .s1 = {{ | ||
232 | .out = "\e\\142\\040\\134C\007\"\x90\\015]", | ||
233 | .flags = ESCAPE_OCTAL, | ||
234 | },{ | ||
235 | /* terminator */ | ||
236 | }}, | ||
237 | },{ | ||
238 | /* terminator */ | ||
239 | }}; | ||
240 | |||
241 | static __init const char *test_string_find_match(const struct test_string_2 *s2, | ||
242 | unsigned int flags) | ||
243 | { | ||
244 | const struct test_string_1 *s1 = s2->s1; | ||
245 | unsigned int i; | ||
246 | |||
247 | if (!flags) | ||
248 | return s2->in; | ||
249 | |||
250 | /* Test cases are NULL-aware */ | ||
251 | flags &= ~ESCAPE_NULL; | ||
252 | |||
253 | /* ESCAPE_OCTAL has a higher priority */ | ||
254 | if (flags & ESCAPE_OCTAL) | ||
255 | flags &= ~ESCAPE_HEX; | ||
256 | |||
257 | for (i = 0; i < TEST_STRING_2_MAX_S1 && s1->out; i++, s1++) | ||
258 | if (s1->flags == flags) | ||
259 | return s1->out; | ||
260 | return NULL; | ||
261 | } | ||
262 | |||
263 | static __init void test_string_escape(const char *name, | ||
264 | const struct test_string_2 *s2, | ||
265 | unsigned int flags, const char *esc) | ||
266 | { | ||
267 | int q_real = 512; | ||
268 | char *out_test = kmalloc(q_real, GFP_KERNEL); | ||
269 | char *out_real = kmalloc(q_real, GFP_KERNEL); | ||
270 | char *in = kmalloc(256, GFP_KERNEL); | ||
271 | char *buf = out_real; | ||
272 | int p = 0, q_test = 0; | ||
273 | |||
274 | if (!out_test || !out_real || !in) | ||
275 | goto out; | ||
276 | |||
277 | for (; s2->in; s2++) { | ||
278 | const char *out; | ||
279 | int len; | ||
280 | |||
281 | /* NULL injection */ | ||
282 | if (flags & ESCAPE_NULL) { | ||
283 | in[p++] = '\0'; | ||
284 | out_test[q_test++] = '\\'; | ||
285 | out_test[q_test++] = '0'; | ||
286 | } | ||
287 | |||
288 | /* Don't try strings that have no output */ | ||
289 | out = test_string_find_match(s2, flags); | ||
290 | if (!out) | ||
291 | continue; | ||
292 | |||
293 | /* Copy string to in buffer */ | ||
294 | len = strlen(s2->in); | ||
295 | memcpy(&in[p], s2->in, len); | ||
296 | p += len; | ||
297 | |||
298 | /* Copy expected result for given flags */ | ||
299 | len = strlen(out); | ||
300 | memcpy(&out_test[q_test], out, len); | ||
301 | q_test += len; | ||
302 | } | ||
303 | |||
304 | q_real = string_escape_mem(in, p, &buf, q_real, flags, esc); | ||
305 | |||
306 | test_string_check_buf(name, flags, in, p, out_real, q_real, out_test, | ||
307 | q_test); | ||
308 | out: | ||
309 | kfree(in); | ||
310 | kfree(out_real); | ||
311 | kfree(out_test); | ||
312 | } | ||
313 | |||
314 | static __init void test_string_escape_nomem(void) | ||
315 | { | ||
316 | char *in = "\eb \\C\007\"\x90\r]"; | ||
317 | char out[64], *buf = out; | ||
318 | int rc = -ENOMEM, ret; | ||
319 | |||
320 | ret = string_escape_str_any_np(in, &buf, strlen(in), NULL); | ||
321 | if (ret == rc) | ||
322 | return; | ||
323 | |||
324 | pr_err("Test 'escape nomem' failed: got %d instead of %d\n", ret, rc); | ||
103 | } | 325 | } |
104 | 326 | ||
105 | static int __init test_string_helpers_init(void) | 327 | static int __init test_string_helpers_init(void) |
@@ -112,6 +334,16 @@ static int __init test_string_helpers_init(void) | |||
112 | test_string_unescape("unescape inplace", | 334 | test_string_unescape("unescape inplace", |
113 | get_random_int() % (UNESCAPE_ANY + 1), true); | 335 | get_random_int() % (UNESCAPE_ANY + 1), true); |
114 | 336 | ||
337 | /* Without dictionary */ | ||
338 | for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++) | ||
339 | test_string_escape("escape 0", escape0, i, TEST_STRING_2_DICT_0); | ||
340 | |||
341 | /* With dictionary */ | ||
342 | for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++) | ||
343 | test_string_escape("escape 1", escape1, i, TEST_STRING_2_DICT_1); | ||
344 | |||
345 | test_string_escape_nomem(); | ||
346 | |||
115 | return -EINVAL; | 347 | return -EINVAL; |
116 | } | 348 | } |
117 | module_init(test_string_helpers_init); | 349 | module_init(test_string_helpers_init); |