diff options
Diffstat (limited to 'fs/udf/unicode.c')
-rw-r--r-- | fs/udf/unicode.c | 146 |
1 files changed, 45 insertions, 101 deletions
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index 5599e7535401..dc5990f4c952 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c | |||
@@ -28,53 +28,8 @@ | |||
28 | 28 | ||
29 | #include "udf_sb.h" | 29 | #include "udf_sb.h" |
30 | 30 | ||
31 | static int udf_translate_to_linux(uint8_t *, int, uint8_t *, int, uint8_t *, | 31 | static int udf_translate_to_linux(uint8_t *, int, const uint8_t *, int, |
32 | int); | 32 | const uint8_t *, int); |
33 | |||
34 | static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) | ||
35 | { | ||
36 | if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN)) | ||
37 | return 0; | ||
38 | |||
39 | memset(dest, 0, sizeof(struct ustr)); | ||
40 | memcpy(dest->u_name, src, strlen); | ||
41 | dest->u_cmpID = 0x08; | ||
42 | dest->u_len = strlen; | ||
43 | |||
44 | return strlen; | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * udf_build_ustr | ||
49 | */ | ||
50 | int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) | ||
51 | { | ||
52 | int usesize; | ||
53 | |||
54 | if (!dest || !ptr || !size) | ||
55 | return -1; | ||
56 | BUG_ON(size < 2); | ||
57 | |||
58 | usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name)); | ||
59 | usesize = min(usesize, size - 2); | ||
60 | dest->u_cmpID = ptr[0]; | ||
61 | dest->u_len = usesize; | ||
62 | memcpy(dest->u_name, ptr + 1, usesize); | ||
63 | memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * udf_build_ustr_exact | ||
70 | */ | ||
71 | static void udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) | ||
72 | { | ||
73 | memset(dest, 0, sizeof(struct ustr)); | ||
74 | dest->u_cmpID = ptr[0]; | ||
75 | dest->u_len = exactsize - 1; | ||
76 | memcpy(dest->u_name, ptr + 1, exactsize - 1); | ||
77 | } | ||
78 | 33 | ||
79 | static int udf_uni2char_utf8(wchar_t uni, | 34 | static int udf_uni2char_utf8(wchar_t uni, |
80 | unsigned char *out, | 35 | unsigned char *out, |
@@ -159,53 +114,50 @@ static int udf_char2uni_utf8(const unsigned char *in, | |||
159 | return u_len; | 114 | return u_len; |
160 | } | 115 | } |
161 | 116 | ||
162 | static int udf_name_from_CS0(struct ustr *utf_o, | 117 | static int udf_name_from_CS0(uint8_t *str_o, int str_max_len, |
163 | const struct ustr *ocu_i, | 118 | const uint8_t *ocu, int ocu_len, |
164 | int (*conv_f)(wchar_t, unsigned char *, int)) | 119 | int (*conv_f)(wchar_t, unsigned char *, int)) |
165 | { | 120 | { |
166 | const uint8_t *ocu; | 121 | uint8_t cmp_id; |
167 | uint8_t cmp_id, ocu_len; | ||
168 | int i, len; | 122 | int i, len; |
123 | int str_o_len = 0; | ||
169 | 124 | ||
125 | if (str_max_len <= 0) | ||
126 | return 0; | ||
170 | 127 | ||
171 | ocu_len = ocu_i->u_len; | ||
172 | if (ocu_len == 0) { | 128 | if (ocu_len == 0) { |
173 | memset(utf_o, 0, sizeof(struct ustr)); | 129 | memset(str_o, 0, str_max_len); |
174 | return 0; | 130 | return 0; |
175 | } | 131 | } |
176 | 132 | ||
177 | cmp_id = ocu_i->u_cmpID; | 133 | cmp_id = ocu[0]; |
178 | if (cmp_id != 8 && cmp_id != 16) { | 134 | if (cmp_id != 8 && cmp_id != 16) { |
179 | memset(utf_o, 0, sizeof(struct ustr)); | 135 | memset(str_o, 0, str_max_len); |
180 | pr_err("unknown compression code (%d) stri=%s\n", | 136 | pr_err("unknown compression code (%d) stri=%s\n", cmp_id, ocu); |
181 | cmp_id, ocu_i->u_name); | ||
182 | return -EINVAL; | 137 | return -EINVAL; |
183 | } | 138 | } |
184 | 139 | ||
185 | ocu = ocu_i->u_name; | 140 | for (i = 1; (i < ocu_len) && (str_o_len < str_max_len);) { |
186 | utf_o->u_len = 0; | ||
187 | for (i = 0; (i < ocu_len) && (utf_o->u_len < UDF_NAME_LEN);) { | ||
188 | /* Expand OSTA compressed Unicode to Unicode */ | 141 | /* Expand OSTA compressed Unicode to Unicode */ |
189 | uint32_t c = ocu[i++]; | 142 | uint32_t c = ocu[i++]; |
190 | if (cmp_id == 16) | 143 | if (cmp_id == 16) |
191 | c = (c << 8) | ocu[i++]; | 144 | c = (c << 8) | ocu[i++]; |
192 | 145 | ||
193 | len = conv_f(c, &utf_o->u_name[utf_o->u_len], | 146 | len = conv_f(c, &str_o[str_o_len], str_max_len - str_o_len); |
194 | UDF_NAME_LEN - utf_o->u_len); | ||
195 | /* Valid character? */ | 147 | /* Valid character? */ |
196 | if (len >= 0) | 148 | if (len >= 0) |
197 | utf_o->u_len += len; | 149 | str_o_len += len; |
198 | else if (len == -ENAMETOOLONG) | 150 | else if (len == -ENAMETOOLONG) |
199 | break; | 151 | break; |
200 | else | 152 | else |
201 | utf_o->u_name[utf_o->u_len++] = '?'; | 153 | str_o[str_o_len++] = '?'; |
202 | } | 154 | } |
203 | utf_o->u_cmpID = 8; | ||
204 | 155 | ||
205 | return utf_o->u_len; | 156 | return str_o_len; |
206 | } | 157 | } |
207 | 158 | ||
208 | static int udf_name_to_CS0(dstring *ocu, struct ustr *uni, int length, | 159 | static int udf_name_to_CS0(uint8_t *ocu, int ocu_max_len, |
160 | const uint8_t *str_i, int str_len, | ||
209 | int (*conv_f)(const unsigned char *, int, wchar_t *)) | 161 | int (*conv_f)(const unsigned char *, int, wchar_t *)) |
210 | { | 162 | { |
211 | int i, len; | 163 | int i, len; |
@@ -213,18 +165,21 @@ static int udf_name_to_CS0(dstring *ocu, struct ustr *uni, int length, | |||
213 | wchar_t uni_char; | 165 | wchar_t uni_char; |
214 | int u_len, u_ch; | 166 | int u_len, u_ch; |
215 | 167 | ||
216 | memset(ocu, 0, sizeof(dstring) * length); | 168 | if (ocu_max_len <= 0) |
169 | return 0; | ||
170 | |||
171 | memset(ocu, 0, ocu_max_len); | ||
217 | ocu[0] = 8; | 172 | ocu[0] = 8; |
218 | max_val = 0xff; | 173 | max_val = 0xff; |
219 | u_ch = 1; | 174 | u_ch = 1; |
220 | 175 | ||
221 | try_again: | 176 | try_again: |
222 | u_len = 0; | 177 | u_len = 1; |
223 | for (i = 0; i < uni->u_len; i++) { | 178 | for (i = 0; i < str_len; i++) { |
224 | /* Name didn't fit? */ | 179 | /* Name didn't fit? */ |
225 | if (u_len + 1 + u_ch >= length) | 180 | if (u_len + u_ch > ocu_max_len) |
226 | return 0; | 181 | return 0; |
227 | len = conv_f(&uni->u_name[i], uni->u_len - i, &uni_char); | 182 | len = conv_f(&str_i[i], str_len - i, &uni_char); |
228 | if (!len) | 183 | if (!len) |
229 | continue; | 184 | continue; |
230 | /* Invalid character, deal with it */ | 185 | /* Invalid character, deal with it */ |
@@ -241,41 +196,37 @@ try_again: | |||
241 | } | 196 | } |
242 | 197 | ||
243 | if (max_val == 0xffff) | 198 | if (max_val == 0xffff) |
244 | ocu[++u_len] = (uint8_t)(uni_char >> 8); | 199 | ocu[u_len++] = (uint8_t)(uni_char >> 8); |
245 | ocu[++u_len] = (uint8_t)(uni_char & 0xff); | 200 | ocu[u_len++] = (uint8_t)(uni_char & 0xff); |
246 | i += len - 1; | 201 | i += len - 1; |
247 | } | 202 | } |
248 | 203 | ||
249 | ocu[length - 1] = (uint8_t)u_len + 1; | 204 | return u_len; |
250 | return u_len + 1; | ||
251 | } | 205 | } |
252 | 206 | ||
253 | int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) | 207 | int udf_CS0toUTF8(uint8_t *utf_o, int o_len, const uint8_t *ocu_i, int i_len) |
254 | { | 208 | { |
255 | return udf_name_from_CS0(utf_o, ocu_i, udf_uni2char_utf8); | 209 | return udf_name_from_CS0(utf_o, o_len, ocu_i, i_len, |
210 | udf_uni2char_utf8); | ||
256 | } | 211 | } |
257 | 212 | ||
258 | int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen, | 213 | int udf_get_filename(struct super_block *sb, const uint8_t *sname, int slen, |
259 | uint8_t *dname, int dlen) | 214 | uint8_t *dname, int dlen) |
260 | { | 215 | { |
261 | struct ustr *filename, *unifilename; | 216 | uint8_t *filename; |
262 | int (*conv_f)(wchar_t, unsigned char *, int); | 217 | int (*conv_f)(wchar_t, unsigned char *, int); |
263 | int ret; | 218 | int ret; |
264 | 219 | ||
265 | if (!slen) | 220 | if (!slen) |
266 | return -EIO; | 221 | return -EIO; |
267 | 222 | ||
268 | filename = kmalloc(sizeof(struct ustr), GFP_NOFS); | 223 | if (dlen <= 0) |
224 | return 0; | ||
225 | |||
226 | filename = kmalloc(dlen, GFP_NOFS); | ||
269 | if (!filename) | 227 | if (!filename) |
270 | return -ENOMEM; | 228 | return -ENOMEM; |
271 | 229 | ||
272 | unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS); | ||
273 | if (!unifilename) { | ||
274 | ret = -ENOMEM; | ||
275 | goto out1; | ||
276 | } | ||
277 | |||
278 | udf_build_ustr_exact(unifilename, sname, slen); | ||
279 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { | 230 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { |
280 | conv_f = udf_uni2char_utf8; | 231 | conv_f = udf_uni2char_utf8; |
281 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { | 232 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { |
@@ -283,21 +234,18 @@ int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen, | |||
283 | } else | 234 | } else |
284 | BUG(); | 235 | BUG(); |
285 | 236 | ||
286 | ret = udf_name_from_CS0(filename, unifilename, conv_f); | 237 | ret = udf_name_from_CS0(filename, dlen, sname, slen, conv_f); |
287 | if (ret < 0) { | 238 | if (ret < 0) { |
288 | udf_debug("Failed in udf_get_filename: sname = %s\n", sname); | 239 | udf_debug("Failed in udf_get_filename: sname = %s\n", sname); |
289 | goto out2; | 240 | goto out2; |
290 | } | 241 | } |
291 | 242 | ||
292 | ret = udf_translate_to_linux(dname, dlen, | 243 | ret = udf_translate_to_linux(dname, dlen, filename, dlen, |
293 | filename->u_name, filename->u_len, | 244 | sname + 1, slen - 1); |
294 | unifilename->u_name, unifilename->u_len); | ||
295 | /* Zero length filename isn't valid... */ | 245 | /* Zero length filename isn't valid... */ |
296 | if (ret == 0) | 246 | if (ret == 0) |
297 | ret = -EINVAL; | 247 | ret = -EINVAL; |
298 | out2: | 248 | out2: |
299 | kfree(unifilename); | ||
300 | out1: | ||
301 | kfree(filename); | 249 | kfree(filename); |
302 | return ret; | 250 | return ret; |
303 | } | 251 | } |
@@ -305,12 +253,8 @@ out1: | |||
305 | int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen, | 253 | int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen, |
306 | uint8_t *dname, int dlen) | 254 | uint8_t *dname, int dlen) |
307 | { | 255 | { |
308 | struct ustr unifilename; | ||
309 | int (*conv_f)(const unsigned char *, int, wchar_t *); | 256 | int (*conv_f)(const unsigned char *, int, wchar_t *); |
310 | 257 | ||
311 | if (!udf_char_to_ustr(&unifilename, sname, slen)) | ||
312 | return 0; | ||
313 | |||
314 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { | 258 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { |
315 | conv_f = udf_char2uni_utf8; | 259 | conv_f = udf_char2uni_utf8; |
316 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { | 260 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { |
@@ -318,7 +262,7 @@ int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen, | |||
318 | } else | 262 | } else |
319 | BUG(); | 263 | BUG(); |
320 | 264 | ||
321 | return udf_name_to_CS0(dname, &unifilename, dlen, conv_f); | 265 | return udf_name_to_CS0(dname, dlen, sname, slen, conv_f); |
322 | } | 266 | } |
323 | 267 | ||
324 | #define ILLEGAL_CHAR_MARK '_' | 268 | #define ILLEGAL_CHAR_MARK '_' |
@@ -329,8 +273,8 @@ int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen, | |||
329 | #define CRC_LEN 5 | 273 | #define CRC_LEN 5 |
330 | 274 | ||
331 | static int udf_translate_to_linux(uint8_t *newName, int newLen, | 275 | static int udf_translate_to_linux(uint8_t *newName, int newLen, |
332 | uint8_t *udfName, int udfLen, | 276 | const uint8_t *udfName, int udfLen, |
333 | uint8_t *fidName, int fidNameLen) | 277 | const uint8_t *fidName, int fidNameLen) |
334 | { | 278 | { |
335 | int index, newIndex = 0, needsCRC = 0; | 279 | int index, newIndex = 0, needsCRC = 0; |
336 | int extIndex = 0, newExtIndex = 0, hasExt = 0; | 280 | int extIndex = 0, newExtIndex = 0, hasExt = 0; |