summaryrefslogtreecommitdiffstats
path: root/fs/udf/unicode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/udf/unicode.c')
-rw-r--r--fs/udf/unicode.c146
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
31static int udf_translate_to_linux(uint8_t *, int, uint8_t *, int, uint8_t *, 31static int udf_translate_to_linux(uint8_t *, int, const uint8_t *, int,
32 int); 32 const uint8_t *, int);
33
34static 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 */
50int 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 */
71static 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
79static int udf_uni2char_utf8(wchar_t uni, 34static 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
162static int udf_name_from_CS0(struct ustr *utf_o, 117static 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
208static int udf_name_to_CS0(dstring *ocu, struct ustr *uni, int length, 159static 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
221try_again: 176try_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
253int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) 207int 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
258int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen, 213int 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;
298out2: 248out2:
299 kfree(unifilename);
300out1:
301 kfree(filename); 249 kfree(filename);
302 return ret; 250 return ret;
303} 251}
@@ -305,12 +253,8 @@ out1:
305int udf_put_filename(struct super_block *sb, const uint8_t *sname, int slen, 253int 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
331static int udf_translate_to_linux(uint8_t *newName, int newLen, 275static 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;