diff options
Diffstat (limited to 'fs/udf/unicode.c')
-rw-r--r-- | fs/udf/unicode.c | 630 |
1 files changed, 250 insertions, 380 deletions
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index e788a05aab83..3ff42f4437f3 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c | |||
@@ -28,199 +28,72 @@ | |||
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_uni2char_utf8(wchar_t uni, |
32 | int); | 32 | unsigned char *out, |
33 | 33 | int boundlen) | |
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 - 2)) | ||
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 | |||
79 | /* | ||
80 | * udf_CS0toUTF8 | ||
81 | * | ||
82 | * PURPOSE | ||
83 | * Convert OSTA Compressed Unicode to the UTF-8 equivalent. | ||
84 | * | ||
85 | * PRE-CONDITIONS | ||
86 | * utf Pointer to UTF-8 output buffer. | ||
87 | * ocu Pointer to OSTA Compressed Unicode input buffer | ||
88 | * of size UDF_NAME_LEN bytes. | ||
89 | * both of type "struct ustr *" | ||
90 | * | ||
91 | * POST-CONDITIONS | ||
92 | * <return> >= 0 on success. | ||
93 | * | ||
94 | * HISTORY | ||
95 | * November 12, 1997 - Andrew E. Mileski | ||
96 | * Written, tested, and released. | ||
97 | */ | ||
98 | int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) | ||
99 | { | 34 | { |
100 | const uint8_t *ocu; | 35 | int u_len = 0; |
101 | uint8_t cmp_id, ocu_len; | 36 | |
102 | int i; | 37 | if (boundlen <= 0) |
103 | 38 | return -ENAMETOOLONG; | |
104 | ocu_len = ocu_i->u_len; | 39 | |
105 | if (ocu_len == 0) { | 40 | if (uni < 0x80) { |
106 | memset(utf_o, 0, sizeof(struct ustr)); | 41 | out[u_len++] = (unsigned char)uni; |
107 | return 0; | 42 | } else if (uni < 0x800) { |
108 | } | 43 | if (boundlen < 2) |
109 | 44 | return -ENAMETOOLONG; | |
110 | cmp_id = ocu_i->u_cmpID; | 45 | out[u_len++] = (unsigned char)(0xc0 | (uni >> 6)); |
111 | if (cmp_id != 8 && cmp_id != 16) { | 46 | out[u_len++] = (unsigned char)(0x80 | (uni & 0x3f)); |
112 | memset(utf_o, 0, sizeof(struct ustr)); | 47 | } else { |
113 | pr_err("unknown compression code (%d) stri=%s\n", | 48 | if (boundlen < 3) |
114 | cmp_id, ocu_i->u_name); | 49 | return -ENAMETOOLONG; |
115 | return -EINVAL; | 50 | out[u_len++] = (unsigned char)(0xe0 | (uni >> 12)); |
116 | } | 51 | out[u_len++] = (unsigned char)(0x80 | ((uni >> 6) & 0x3f)); |
117 | 52 | out[u_len++] = (unsigned char)(0x80 | (uni & 0x3f)); | |
118 | ocu = ocu_i->u_name; | ||
119 | utf_o->u_len = 0; | ||
120 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { | ||
121 | |||
122 | /* Expand OSTA compressed Unicode to Unicode */ | ||
123 | uint32_t c = ocu[i++]; | ||
124 | if (cmp_id == 16) | ||
125 | c = (c << 8) | ocu[i++]; | ||
126 | |||
127 | /* Compress Unicode to UTF-8 */ | ||
128 | if (c < 0x80U) | ||
129 | utf_o->u_name[utf_o->u_len++] = (uint8_t)c; | ||
130 | else if (c < 0x800U) { | ||
131 | if (utf_o->u_len > (UDF_NAME_LEN - 4)) | ||
132 | break; | ||
133 | utf_o->u_name[utf_o->u_len++] = | ||
134 | (uint8_t)(0xc0 | (c >> 6)); | ||
135 | utf_o->u_name[utf_o->u_len++] = | ||
136 | (uint8_t)(0x80 | (c & 0x3f)); | ||
137 | } else { | ||
138 | if (utf_o->u_len > (UDF_NAME_LEN - 5)) | ||
139 | break; | ||
140 | utf_o->u_name[utf_o->u_len++] = | ||
141 | (uint8_t)(0xe0 | (c >> 12)); | ||
142 | utf_o->u_name[utf_o->u_len++] = | ||
143 | (uint8_t)(0x80 | | ||
144 | ((c >> 6) & 0x3f)); | ||
145 | utf_o->u_name[utf_o->u_len++] = | ||
146 | (uint8_t)(0x80 | (c & 0x3f)); | ||
147 | } | ||
148 | } | 53 | } |
149 | utf_o->u_cmpID = 8; | 54 | return u_len; |
150 | |||
151 | return utf_o->u_len; | ||
152 | } | 55 | } |
153 | 56 | ||
154 | /* | 57 | static int udf_char2uni_utf8(const unsigned char *in, |
155 | * | 58 | int boundlen, |
156 | * udf_UTF8toCS0 | 59 | wchar_t *uni) |
157 | * | ||
158 | * PURPOSE | ||
159 | * Convert UTF-8 to the OSTA Compressed Unicode equivalent. | ||
160 | * | ||
161 | * DESCRIPTION | ||
162 | * This routine is only called by udf_lookup(). | ||
163 | * | ||
164 | * PRE-CONDITIONS | ||
165 | * ocu Pointer to OSTA Compressed Unicode output | ||
166 | * buffer of size UDF_NAME_LEN bytes. | ||
167 | * utf Pointer to UTF-8 input buffer. | ||
168 | * utf_len Length of UTF-8 input buffer in bytes. | ||
169 | * | ||
170 | * POST-CONDITIONS | ||
171 | * <return> Zero on success. | ||
172 | * | ||
173 | * HISTORY | ||
174 | * November 12, 1997 - Andrew E. Mileski | ||
175 | * Written, tested, and released. | ||
176 | */ | ||
177 | static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) | ||
178 | { | 60 | { |
179 | unsigned c, i, max_val, utf_char; | 61 | unsigned int utf_char; |
180 | int utf_cnt, u_len, u_ch; | 62 | unsigned char c; |
181 | 63 | int utf_cnt, u_len; | |
182 | memset(ocu, 0, sizeof(dstring) * length); | ||
183 | ocu[0] = 8; | ||
184 | max_val = 0xffU; | ||
185 | u_ch = 1; | ||
186 | 64 | ||
187 | try_again: | 65 | utf_char = 0; |
188 | u_len = 0U; | 66 | utf_cnt = 0; |
189 | utf_char = 0U; | 67 | for (u_len = 0; u_len < boundlen;) { |
190 | utf_cnt = 0U; | 68 | c = in[u_len++]; |
191 | for (i = 0U; i < utf->u_len; i++) { | ||
192 | /* Name didn't fit? */ | ||
193 | if (u_len + 1 + u_ch >= length) | ||
194 | return 0; | ||
195 | |||
196 | c = (uint8_t)utf->u_name[i]; | ||
197 | 69 | ||
198 | /* Complete a multi-byte UTF-8 character */ | 70 | /* Complete a multi-byte UTF-8 character */ |
199 | if (utf_cnt) { | 71 | if (utf_cnt) { |
200 | utf_char = (utf_char << 6) | (c & 0x3fU); | 72 | utf_char = (utf_char << 6) | (c & 0x3f); |
201 | if (--utf_cnt) | 73 | if (--utf_cnt) |
202 | continue; | 74 | continue; |
203 | } else { | 75 | } else { |
204 | /* Check for a multi-byte UTF-8 character */ | 76 | /* Check for a multi-byte UTF-8 character */ |
205 | if (c & 0x80U) { | 77 | if (c & 0x80) { |
206 | /* Start a multi-byte UTF-8 character */ | 78 | /* Start a multi-byte UTF-8 character */ |
207 | if ((c & 0xe0U) == 0xc0U) { | 79 | if ((c & 0xe0) == 0xc0) { |
208 | utf_char = c & 0x1fU; | 80 | utf_char = c & 0x1f; |
209 | utf_cnt = 1; | 81 | utf_cnt = 1; |
210 | } else if ((c & 0xf0U) == 0xe0U) { | 82 | } else if ((c & 0xf0) == 0xe0) { |
211 | utf_char = c & 0x0fU; | 83 | utf_char = c & 0x0f; |
212 | utf_cnt = 2; | 84 | utf_cnt = 2; |
213 | } else if ((c & 0xf8U) == 0xf0U) { | 85 | } else if ((c & 0xf8) == 0xf0) { |
214 | utf_char = c & 0x07U; | 86 | utf_char = c & 0x07; |
215 | utf_cnt = 3; | 87 | utf_cnt = 3; |
216 | } else if ((c & 0xfcU) == 0xf8U) { | 88 | } else if ((c & 0xfc) == 0xf8) { |
217 | utf_char = c & 0x03U; | 89 | utf_char = c & 0x03; |
218 | utf_cnt = 4; | 90 | utf_cnt = 4; |
219 | } else if ((c & 0xfeU) == 0xfcU) { | 91 | } else if ((c & 0xfe) == 0xfc) { |
220 | utf_char = c & 0x01U; | 92 | utf_char = c & 0x01; |
221 | utf_cnt = 5; | 93 | utf_cnt = 5; |
222 | } else { | 94 | } else { |
223 | goto error_out; | 95 | utf_cnt = -1; |
96 | break; | ||
224 | } | 97 | } |
225 | continue; | 98 | continue; |
226 | } else { | 99 | } else { |
@@ -228,97 +101,216 @@ try_again: | |||
228 | utf_char = c; | 101 | utf_char = c; |
229 | } | 102 | } |
230 | } | 103 | } |
231 | 104 | *uni = utf_char; | |
232 | /* Choose no compression if necessary */ | 105 | break; |
233 | if (utf_char > max_val) { | ||
234 | if (max_val == 0xffU) { | ||
235 | max_val = 0xffffU; | ||
236 | ocu[0] = (uint8_t)0x10U; | ||
237 | u_ch = 2; | ||
238 | goto try_again; | ||
239 | } | ||
240 | goto error_out; | ||
241 | } | ||
242 | |||
243 | if (max_val == 0xffffU) | ||
244 | ocu[++u_len] = (uint8_t)(utf_char >> 8); | ||
245 | ocu[++u_len] = (uint8_t)(utf_char & 0xffU); | ||
246 | } | 106 | } |
247 | |||
248 | if (utf_cnt) { | 107 | if (utf_cnt) { |
249 | error_out: | 108 | *uni = '?'; |
250 | ocu[++u_len] = '?'; | 109 | return -EINVAL; |
251 | printk(KERN_DEBUG pr_fmt("bad UTF-8 character\n")); | ||
252 | } | 110 | } |
111 | return u_len; | ||
112 | } | ||
253 | 113 | ||
254 | ocu[length - 1] = (uint8_t)u_len + 1; | 114 | #define ILLEGAL_CHAR_MARK '_' |
115 | #define EXT_MARK '.' | ||
116 | #define CRC_MARK '#' | ||
117 | #define EXT_SIZE 5 | ||
118 | /* Number of chars we need to store generated CRC to make filename unique */ | ||
119 | #define CRC_LEN 5 | ||
120 | |||
121 | static int udf_name_conv_char(uint8_t *str_o, int str_o_max_len, | ||
122 | int *str_o_idx, | ||
123 | const uint8_t *str_i, int str_i_max_len, | ||
124 | int *str_i_idx, | ||
125 | int u_ch, int *needsCRC, | ||
126 | int (*conv_f)(wchar_t, unsigned char *, int), | ||
127 | int translate) | ||
128 | { | ||
129 | uint32_t c; | ||
130 | int illChar = 0; | ||
131 | int len, gotch = 0; | ||
132 | |||
133 | for (; (!gotch) && (*str_i_idx < str_i_max_len); *str_i_idx += u_ch) { | ||
134 | if (*str_o_idx >= str_o_max_len) { | ||
135 | *needsCRC = 1; | ||
136 | return gotch; | ||
137 | } | ||
255 | 138 | ||
256 | return u_len + 1; | 139 | /* Expand OSTA compressed Unicode to Unicode */ |
140 | c = str_i[*str_i_idx]; | ||
141 | if (u_ch > 1) | ||
142 | c = (c << 8) | str_i[*str_i_idx + 1]; | ||
143 | |||
144 | if (translate && (c == '/' || c == 0)) | ||
145 | illChar = 1; | ||
146 | else if (illChar) | ||
147 | break; | ||
148 | else | ||
149 | gotch = 1; | ||
150 | } | ||
151 | if (illChar) { | ||
152 | *needsCRC = 1; | ||
153 | c = ILLEGAL_CHAR_MARK; | ||
154 | gotch = 1; | ||
155 | } | ||
156 | if (gotch) { | ||
157 | len = conv_f(c, &str_o[*str_o_idx], str_o_max_len - *str_o_idx); | ||
158 | /* Valid character? */ | ||
159 | if (len >= 0) | ||
160 | *str_o_idx += len; | ||
161 | else if (len == -ENAMETOOLONG) { | ||
162 | *needsCRC = 1; | ||
163 | gotch = 0; | ||
164 | } else { | ||
165 | str_o[(*str_o_idx)++] = '?'; | ||
166 | *needsCRC = 1; | ||
167 | } | ||
168 | } | ||
169 | return gotch; | ||
257 | } | 170 | } |
258 | 171 | ||
259 | static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, | 172 | static int udf_name_from_CS0(uint8_t *str_o, int str_max_len, |
260 | const struct ustr *ocu_i) | 173 | const uint8_t *ocu, int ocu_len, |
174 | int (*conv_f)(wchar_t, unsigned char *, int), | ||
175 | int translate) | ||
261 | { | 176 | { |
262 | const uint8_t *ocu; | 177 | uint32_t c; |
263 | uint8_t cmp_id, ocu_len; | 178 | uint8_t cmp_id; |
264 | int i, len; | 179 | int idx, len; |
180 | int u_ch; | ||
181 | int needsCRC = 0; | ||
182 | int ext_i_len, ext_max_len; | ||
183 | int str_o_len = 0; /* Length of resulting output */ | ||
184 | int ext_o_len = 0; /* Extension output length */ | ||
185 | int ext_crc_len = 0; /* Extension output length if used with CRC */ | ||
186 | int i_ext = -1; /* Extension position in input buffer */ | ||
187 | int o_crc = 0; /* Rightmost possible output pos for CRC+ext */ | ||
188 | unsigned short valueCRC; | ||
189 | uint8_t ext[EXT_SIZE * NLS_MAX_CHARSET_SIZE + 1]; | ||
190 | uint8_t crc[CRC_LEN]; | ||
265 | 191 | ||
192 | if (str_max_len <= 0) | ||
193 | return 0; | ||
266 | 194 | ||
267 | ocu_len = ocu_i->u_len; | ||
268 | if (ocu_len == 0) { | 195 | if (ocu_len == 0) { |
269 | memset(utf_o, 0, sizeof(struct ustr)); | 196 | memset(str_o, 0, str_max_len); |
270 | return 0; | 197 | return 0; |
271 | } | 198 | } |
272 | 199 | ||
273 | cmp_id = ocu_i->u_cmpID; | 200 | cmp_id = ocu[0]; |
274 | if (cmp_id != 8 && cmp_id != 16) { | 201 | if (cmp_id != 8 && cmp_id != 16) { |
275 | memset(utf_o, 0, sizeof(struct ustr)); | 202 | memset(str_o, 0, str_max_len); |
276 | pr_err("unknown compression code (%d) stri=%s\n", | 203 | pr_err("unknown compression code (%d)\n", cmp_id); |
277 | cmp_id, ocu_i->u_name); | ||
278 | return -EINVAL; | 204 | return -EINVAL; |
279 | } | 205 | } |
206 | u_ch = cmp_id >> 3; | ||
280 | 207 | ||
281 | ocu = ocu_i->u_name; | 208 | ocu++; |
282 | utf_o->u_len = 0; | 209 | ocu_len--; |
283 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { | ||
284 | /* Expand OSTA compressed Unicode to Unicode */ | ||
285 | uint32_t c = ocu[i++]; | ||
286 | if (cmp_id == 16) | ||
287 | c = (c << 8) | ocu[i++]; | ||
288 | 210 | ||
289 | len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len], | 211 | if (ocu_len % u_ch) { |
290 | UDF_NAME_LEN - 2 - utf_o->u_len); | 212 | pr_err("incorrect filename length (%d)\n", ocu_len + 1); |
291 | /* Valid character? */ | 213 | return -EINVAL; |
292 | if (len >= 0) | 214 | } |
293 | utf_o->u_len += len; | 215 | |
294 | else | 216 | if (translate) { |
295 | utf_o->u_name[utf_o->u_len++] = '?'; | 217 | /* Look for extension */ |
218 | for (idx = ocu_len - u_ch, ext_i_len = 0; | ||
219 | (idx >= 0) && (ext_i_len < EXT_SIZE); | ||
220 | idx -= u_ch, ext_i_len++) { | ||
221 | c = ocu[idx]; | ||
222 | if (u_ch > 1) | ||
223 | c = (c << 8) | ocu[idx + 1]; | ||
224 | |||
225 | if (c == EXT_MARK) { | ||
226 | if (ext_i_len) | ||
227 | i_ext = idx; | ||
228 | break; | ||
229 | } | ||
230 | } | ||
231 | if (i_ext >= 0) { | ||
232 | /* Convert extension */ | ||
233 | ext_max_len = min_t(int, sizeof(ext), str_max_len); | ||
234 | ext[ext_o_len++] = EXT_MARK; | ||
235 | idx = i_ext + u_ch; | ||
236 | while (udf_name_conv_char(ext, ext_max_len, &ext_o_len, | ||
237 | ocu, ocu_len, &idx, | ||
238 | u_ch, &needsCRC, | ||
239 | conv_f, translate)) { | ||
240 | if ((ext_o_len + CRC_LEN) < str_max_len) | ||
241 | ext_crc_len = ext_o_len; | ||
242 | } | ||
243 | } | ||
296 | } | 244 | } |
297 | utf_o->u_cmpID = 8; | ||
298 | 245 | ||
299 | return utf_o->u_len; | 246 | idx = 0; |
247 | while (1) { | ||
248 | if (translate && (idx == i_ext)) { | ||
249 | if (str_o_len > (str_max_len - ext_o_len)) | ||
250 | needsCRC = 1; | ||
251 | break; | ||
252 | } | ||
253 | |||
254 | if (!udf_name_conv_char(str_o, str_max_len, &str_o_len, | ||
255 | ocu, ocu_len, &idx, | ||
256 | u_ch, &needsCRC, conv_f, translate)) | ||
257 | break; | ||
258 | |||
259 | if (translate && | ||
260 | (str_o_len <= (str_max_len - ext_o_len - CRC_LEN))) | ||
261 | o_crc = str_o_len; | ||
262 | } | ||
263 | |||
264 | if (translate) { | ||
265 | if (str_o_len <= 2 && str_o[0] == '.' && | ||
266 | (str_o_len == 1 || str_o[1] == '.')) | ||
267 | needsCRC = 1; | ||
268 | if (needsCRC) { | ||
269 | str_o_len = o_crc; | ||
270 | valueCRC = crc_itu_t(0, ocu, ocu_len); | ||
271 | crc[0] = CRC_MARK; | ||
272 | crc[1] = hex_asc_upper_hi(valueCRC >> 8); | ||
273 | crc[2] = hex_asc_upper_lo(valueCRC >> 8); | ||
274 | crc[3] = hex_asc_upper_hi(valueCRC); | ||
275 | crc[4] = hex_asc_upper_lo(valueCRC); | ||
276 | len = min_t(int, CRC_LEN, str_max_len - str_o_len); | ||
277 | memcpy(&str_o[str_o_len], crc, len); | ||
278 | str_o_len += len; | ||
279 | ext_o_len = ext_crc_len; | ||
280 | } | ||
281 | if (ext_o_len > 0) { | ||
282 | memcpy(&str_o[str_o_len], ext, ext_o_len); | ||
283 | str_o_len += ext_o_len; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | return str_o_len; | ||
300 | } | 288 | } |
301 | 289 | ||
302 | static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, | 290 | static int udf_name_to_CS0(uint8_t *ocu, int ocu_max_len, |
303 | int length) | 291 | const uint8_t *str_i, int str_len, |
292 | int (*conv_f)(const unsigned char *, int, wchar_t *)) | ||
304 | { | 293 | { |
305 | int len; | 294 | int i, len; |
306 | unsigned i, max_val; | 295 | unsigned int max_val; |
307 | uint16_t uni_char; | 296 | wchar_t uni_char; |
308 | int u_len, u_ch; | 297 | int u_len, u_ch; |
309 | 298 | ||
310 | memset(ocu, 0, sizeof(dstring) * length); | 299 | if (ocu_max_len <= 0) |
300 | return 0; | ||
301 | |||
302 | memset(ocu, 0, ocu_max_len); | ||
311 | ocu[0] = 8; | 303 | ocu[0] = 8; |
312 | max_val = 0xffU; | 304 | max_val = 0xff; |
313 | u_ch = 1; | 305 | u_ch = 1; |
314 | 306 | ||
315 | try_again: | 307 | try_again: |
316 | u_len = 0U; | 308 | u_len = 1; |
317 | for (i = 0U; i < uni->u_len; i++) { | 309 | for (i = 0; i < str_len; i++) { |
318 | /* Name didn't fit? */ | 310 | /* Name didn't fit? */ |
319 | if (u_len + 1 + u_ch >= length) | 311 | if (u_len + u_ch > ocu_max_len) |
320 | return 0; | 312 | return 0; |
321 | len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char); | 313 | len = conv_f(&str_i[i], str_len - i, &uni_char); |
322 | if (!len) | 314 | if (!len) |
323 | continue; | 315 | continue; |
324 | /* Invalid character, deal with it */ | 316 | /* Invalid character, deal with it */ |
@@ -328,187 +320,65 @@ try_again: | |||
328 | } | 320 | } |
329 | 321 | ||
330 | if (uni_char > max_val) { | 322 | if (uni_char > max_val) { |
331 | max_val = 0xffffU; | 323 | max_val = 0xffff; |
332 | ocu[0] = (uint8_t)0x10U; | 324 | ocu[0] = 0x10; |
333 | u_ch = 2; | 325 | u_ch = 2; |
334 | goto try_again; | 326 | goto try_again; |
335 | } | 327 | } |
336 | 328 | ||
337 | if (max_val == 0xffffU) | 329 | if (max_val == 0xffff) |
338 | ocu[++u_len] = (uint8_t)(uni_char >> 8); | 330 | ocu[u_len++] = (uint8_t)(uni_char >> 8); |
339 | ocu[++u_len] = (uint8_t)(uni_char & 0xffU); | 331 | ocu[u_len++] = (uint8_t)(uni_char & 0xff); |
340 | i += len - 1; | 332 | i += len - 1; |
341 | } | 333 | } |
342 | 334 | ||
343 | ocu[length - 1] = (uint8_t)u_len + 1; | 335 | return u_len; |
344 | return u_len + 1; | ||
345 | } | 336 | } |
346 | 337 | ||
347 | int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen, | 338 | int udf_CS0toUTF8(uint8_t *utf_o, int o_len, const uint8_t *ocu_i, int i_len) |
339 | { | ||
340 | return udf_name_from_CS0(utf_o, o_len, ocu_i, i_len, | ||
341 | udf_uni2char_utf8, 0); | ||
342 | } | ||
343 | |||
344 | int udf_get_filename(struct super_block *sb, const uint8_t *sname, int slen, | ||
348 | uint8_t *dname, int dlen) | 345 | uint8_t *dname, int dlen) |
349 | { | 346 | { |
350 | struct ustr *filename, *unifilename; | 347 | int (*conv_f)(wchar_t, unsigned char *, int); |
351 | int ret; | 348 | int ret; |
352 | 349 | ||
353 | if (!slen) | 350 | if (!slen) |
354 | return -EIO; | 351 | return -EIO; |
355 | 352 | ||
356 | filename = kmalloc(sizeof(struct ustr), GFP_NOFS); | 353 | if (dlen <= 0) |
357 | if (!filename) | 354 | return 0; |
358 | return -ENOMEM; | ||
359 | |||
360 | unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS); | ||
361 | if (!unifilename) { | ||
362 | ret = -ENOMEM; | ||
363 | goto out1; | ||
364 | } | ||
365 | 355 | ||
366 | udf_build_ustr_exact(unifilename, sname, slen); | ||
367 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { | 356 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { |
368 | ret = udf_CS0toUTF8(filename, unifilename); | 357 | conv_f = udf_uni2char_utf8; |
369 | if (ret < 0) { | ||
370 | udf_debug("Failed in udf_get_filename: sname = %s\n", | ||
371 | sname); | ||
372 | goto out2; | ||
373 | } | ||
374 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { | 358 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { |
375 | ret = udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename, | 359 | conv_f = UDF_SB(sb)->s_nls_map->uni2char; |
376 | unifilename); | ||
377 | if (ret < 0) { | ||
378 | udf_debug("Failed in udf_get_filename: sname = %s\n", | ||
379 | sname); | ||
380 | goto out2; | ||
381 | } | ||
382 | } else | 360 | } else |
383 | BUG(); | 361 | BUG(); |
384 | 362 | ||
385 | ret = udf_translate_to_linux(dname, dlen, | 363 | ret = udf_name_from_CS0(dname, dlen, sname, slen, conv_f, 1); |
386 | filename->u_name, filename->u_len, | ||
387 | unifilename->u_name, unifilename->u_len); | ||
388 | /* Zero length filename isn't valid... */ | 364 | /* Zero length filename isn't valid... */ |
389 | if (ret == 0) | 365 | if (ret == 0) |
390 | ret = -EINVAL; | 366 | ret = -EINVAL; |
391 | out2: | ||
392 | kfree(unifilename); | ||
393 | out1: | ||
394 | kfree(filename); | ||
395 | return ret; | 367 | return ret; |
396 | } | 368 | } |
397 | 369 | ||
398 | int udf_put_filename(struct super_block *sb, const uint8_t *sname, | 370 | int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen, |
399 | uint8_t *dname, int flen) | 371 | uint8_t *dname, int dlen) |
400 | { | 372 | { |
401 | struct ustr unifilename; | 373 | int (*conv_f)(const unsigned char *, int, wchar_t *); |
402 | int namelen; | ||
403 | |||
404 | if (!udf_char_to_ustr(&unifilename, sname, flen)) | ||
405 | return 0; | ||
406 | 374 | ||
407 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { | 375 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { |
408 | namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN); | 376 | conv_f = udf_char2uni_utf8; |
409 | if (!namelen) | ||
410 | return 0; | ||
411 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { | 377 | } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) { |
412 | namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, | 378 | conv_f = UDF_SB(sb)->s_nls_map->char2uni; |
413 | &unifilename, UDF_NAME_LEN); | ||
414 | if (!namelen) | ||
415 | return 0; | ||
416 | } else | 379 | } else |
417 | return 0; | 380 | BUG(); |
418 | 381 | ||
419 | return namelen; | 382 | return udf_name_to_CS0(dname, dlen, sname, slen, conv_f); |
420 | } | 383 | } |
421 | 384 | ||
422 | #define ILLEGAL_CHAR_MARK '_' | ||
423 | #define EXT_MARK '.' | ||
424 | #define CRC_MARK '#' | ||
425 | #define EXT_SIZE 5 | ||
426 | /* Number of chars we need to store generated CRC to make filename unique */ | ||
427 | #define CRC_LEN 5 | ||
428 | |||
429 | static int udf_translate_to_linux(uint8_t *newName, int newLen, | ||
430 | uint8_t *udfName, int udfLen, | ||
431 | uint8_t *fidName, int fidNameLen) | ||
432 | { | ||
433 | int index, newIndex = 0, needsCRC = 0; | ||
434 | int extIndex = 0, newExtIndex = 0, hasExt = 0; | ||
435 | unsigned short valueCRC; | ||
436 | uint8_t curr; | ||
437 | |||
438 | if (udfName[0] == '.' && | ||
439 | (udfLen == 1 || (udfLen == 2 && udfName[1] == '.'))) { | ||
440 | needsCRC = 1; | ||
441 | newIndex = udfLen; | ||
442 | memcpy(newName, udfName, udfLen); | ||
443 | } else { | ||
444 | for (index = 0; index < udfLen; index++) { | ||
445 | curr = udfName[index]; | ||
446 | if (curr == '/' || curr == 0) { | ||
447 | needsCRC = 1; | ||
448 | curr = ILLEGAL_CHAR_MARK; | ||
449 | while (index + 1 < udfLen && | ||
450 | (udfName[index + 1] == '/' || | ||
451 | udfName[index + 1] == 0)) | ||
452 | index++; | ||
453 | } | ||
454 | if (curr == EXT_MARK && | ||
455 | (udfLen - index - 1) <= EXT_SIZE) { | ||
456 | if (udfLen == index + 1) | ||
457 | hasExt = 0; | ||
458 | else { | ||
459 | hasExt = 1; | ||
460 | extIndex = index; | ||
461 | newExtIndex = newIndex; | ||
462 | } | ||
463 | } | ||
464 | if (newIndex < newLen) | ||
465 | newName[newIndex++] = curr; | ||
466 | else | ||
467 | needsCRC = 1; | ||
468 | } | ||
469 | } | ||
470 | if (needsCRC) { | ||
471 | uint8_t ext[EXT_SIZE]; | ||
472 | int localExtIndex = 0; | ||
473 | |||
474 | if (hasExt) { | ||
475 | int maxFilenameLen; | ||
476 | for (index = 0; | ||
477 | index < EXT_SIZE && extIndex + index + 1 < udfLen; | ||
478 | index++) { | ||
479 | curr = udfName[extIndex + index + 1]; | ||
480 | |||
481 | if (curr == '/' || curr == 0) { | ||
482 | needsCRC = 1; | ||
483 | curr = ILLEGAL_CHAR_MARK; | ||
484 | while (extIndex + index + 2 < udfLen && | ||
485 | (index + 1 < EXT_SIZE && | ||
486 | (udfName[extIndex + index + 2] == '/' || | ||
487 | udfName[extIndex + index + 2] == 0))) | ||
488 | index++; | ||
489 | } | ||
490 | ext[localExtIndex++] = curr; | ||
491 | } | ||
492 | maxFilenameLen = newLen - CRC_LEN - localExtIndex; | ||
493 | if (newIndex > maxFilenameLen) | ||
494 | newIndex = maxFilenameLen; | ||
495 | else | ||
496 | newIndex = newExtIndex; | ||
497 | } else if (newIndex > newLen - CRC_LEN) | ||
498 | newIndex = newLen - CRC_LEN; | ||
499 | newName[newIndex++] = CRC_MARK; | ||
500 | valueCRC = crc_itu_t(0, fidName, fidNameLen); | ||
501 | newName[newIndex++] = hex_asc_upper_hi(valueCRC >> 8); | ||
502 | newName[newIndex++] = hex_asc_upper_lo(valueCRC >> 8); | ||
503 | newName[newIndex++] = hex_asc_upper_hi(valueCRC); | ||
504 | newName[newIndex++] = hex_asc_upper_lo(valueCRC); | ||
505 | |||
506 | if (hasExt) { | ||
507 | newName[newIndex++] = EXT_MARK; | ||
508 | for (index = 0; index < localExtIndex; index++) | ||
509 | newName[newIndex++] = ext[index]; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | return newIndex; | ||
514 | } | ||