diff options
author | Jeff Layton <jlayton@redhat.com> | 2009-04-30 06:46:15 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2009-04-30 11:44:59 -0400 |
commit | 7fabf0c9479fef9fdb9528a5fbdb1cb744a744a4 (patch) | |
tree | a44ab17abeefb87a623d62c344d4aa4b4f1a4b7f | |
parent | 66345f50f070ae7412a28543ee197cb5eff73598 (diff) |
cifs: add replacement for cifs_strtoUCS_le called cifs_from_ucs2
Add a replacement function for cifs_strtoUCS_le. cifs_from_ucs2
takes args for the source and destination length so that we can ensure
that the function is confined within the intended buffers.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Acked-by: Suresh Jayaraman <sjayaraman@suse.de>
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/cifs_unicode.c | 124 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.h | 2 |
2 files changed, 126 insertions, 0 deletions
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 7d75272a6b3f..8389f359b03d 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -26,6 +26,130 @@ | |||
26 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * cifs_mapchar - convert a little-endian char to proper char in codepage | ||
30 | * @target - where converted character should be copied | ||
31 | * @src_char - 2 byte little-endian source character | ||
32 | * @cp - codepage to which character should be converted | ||
33 | * @mapchar - should character be mapped according to mapchars mount option? | ||
34 | * | ||
35 | * This function handles the conversion of a single character. It is the | ||
36 | * responsibility of the caller to ensure that the target buffer is large | ||
37 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | ||
38 | */ | ||
39 | static int | ||
40 | cifs_mapchar(char *target, const __le16 src_char, const struct nls_table *cp, | ||
41 | bool mapchar) | ||
42 | { | ||
43 | int len = 1; | ||
44 | |||
45 | if (!mapchar) | ||
46 | goto cp_convert; | ||
47 | |||
48 | /* | ||
49 | * BB: Cannot handle remapping UNI_SLASH until all the calls to | ||
50 | * build_path_from_dentry are modified, as they use slash as | ||
51 | * separator. | ||
52 | */ | ||
53 | switch (le16_to_cpu(src_char)) { | ||
54 | case UNI_COLON: | ||
55 | *target = ':'; | ||
56 | break; | ||
57 | case UNI_ASTERIK: | ||
58 | *target = '*'; | ||
59 | break; | ||
60 | case UNI_QUESTION: | ||
61 | *target = '?'; | ||
62 | break; | ||
63 | case UNI_PIPE: | ||
64 | *target = '|'; | ||
65 | break; | ||
66 | case UNI_GRTRTHAN: | ||
67 | *target = '>'; | ||
68 | break; | ||
69 | case UNI_LESSTHAN: | ||
70 | *target = '<'; | ||
71 | break; | ||
72 | default: | ||
73 | goto cp_convert; | ||
74 | } | ||
75 | |||
76 | out: | ||
77 | return len; | ||
78 | |||
79 | cp_convert: | ||
80 | len = cp->uni2char(le16_to_cpu(src_char), target, | ||
81 | NLS_MAX_CHARSET_SIZE); | ||
82 | if (len <= 0) { | ||
83 | *target = '?'; | ||
84 | len = 1; | ||
85 | } | ||
86 | goto out; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * cifs_from_ucs2 - convert utf16le string to local charset | ||
91 | * @to - destination buffer | ||
92 | * @from - source buffer | ||
93 | * @tolen - destination buffer size (in bytes) | ||
94 | * @fromlen - source buffer size (in bytes) | ||
95 | * @codepage - codepage to which characters should be converted | ||
96 | * @mapchar - should characters be remapped according to the mapchars option? | ||
97 | * | ||
98 | * Convert a little-endian ucs2le string (as sent by the server) to a string | ||
99 | * in the provided codepage. The tolen and fromlen parameters are to ensure | ||
100 | * that the code doesn't walk off of the end of the buffer (which is always | ||
101 | * a danger if the alignment of the source buffer is off). The destination | ||
102 | * string is always properly null terminated and fits in the destination | ||
103 | * buffer. Returns the length of the destination string in bytes (including | ||
104 | * null terminator). | ||
105 | * | ||
106 | * Note that some windows versions actually send multiword UTF-16 characters | ||
107 | * instead of straight UCS-2. The linux nls routines however aren't able to | ||
108 | * deal with those characters properly. In the event that we get some of | ||
109 | * those characters, they won't be translated properly. | ||
110 | */ | ||
111 | int | ||
112 | cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | ||
113 | const struct nls_table *codepage, bool mapchar) | ||
114 | { | ||
115 | int i, charlen, safelen; | ||
116 | int outlen = 0; | ||
117 | int nullsize = nls_nullsize(codepage); | ||
118 | int fromwords = fromlen / 2; | ||
119 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
120 | |||
121 | /* | ||
122 | * because the chars can be of varying widths, we need to take care | ||
123 | * not to overflow the destination buffer when we get close to the | ||
124 | * end of it. Until we get to this offset, we don't need to check | ||
125 | * for overflow however. | ||
126 | */ | ||
127 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | ||
128 | |||
129 | for (i = 0; i < fromwords && from[i]; i++) { | ||
130 | /* | ||
131 | * check to see if converting this character might make the | ||
132 | * conversion bleed into the null terminator | ||
133 | */ | ||
134 | if (outlen >= safelen) { | ||
135 | charlen = cifs_mapchar(tmp, from[i], codepage, mapchar); | ||
136 | if ((outlen + charlen) > (tolen - nullsize)) | ||
137 | break; | ||
138 | } | ||
139 | |||
140 | /* put converted char into 'to' buffer */ | ||
141 | charlen = cifs_mapchar(&to[outlen], from[i], codepage, mapchar); | ||
142 | outlen += charlen; | ||
143 | } | ||
144 | |||
145 | /* properly null-terminate string */ | ||
146 | for (i = 0; i < nullsize; i++) | ||
147 | to[outlen++] = 0; | ||
148 | |||
149 | return outlen; | ||
150 | } | ||
151 | |||
152 | /* | ||
29 | * NAME: cifs_strfromUCS() | 153 | * NAME: cifs_strfromUCS() |
30 | * | 154 | * |
31 | * FUNCTION: Convert little-endian unicode string to character string | 155 | * FUNCTION: Convert little-endian unicode string to character string |
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index d6fe8ecd1ffc..6aa6533e49fa 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h | |||
@@ -72,6 +72,8 @@ extern struct UniCaseRange UniLowerRange[]; | |||
72 | #endif /* UNIUPR_NOLOWER */ | 72 | #endif /* UNIUPR_NOLOWER */ |
73 | 73 | ||
74 | #ifdef __KERNEL__ | 74 | #ifdef __KERNEL__ |
75 | int cifs_from_ucs2(char *to, const __le16 *from, int tolen, int fromlen, | ||
76 | const struct nls_table *codepage, bool mapchar); | ||
75 | int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); | 77 | int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); |
76 | int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); | 78 | int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); |
77 | #endif | 79 | #endif |