aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-29 23:43:10 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-29 23:43:10 -0500
commitb9d4a35f0a5dd25b85462741a8fb539b355ea95c (patch)
treea4c08e5f651de4d1c324dddf21e7c3149a949387 /fs
parentdf90dcd1007bc498927afea18ccfaae02e361707 (diff)
parent3ee3039c5b4d121d56dc6b7deeeee3ba4150a260 (diff)
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull UDF & isofs fixes from Jan Kara: "A couple of UDF fixes of handling of corrupted media and one iso9660 fix of the same" * 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: udf: Reduce repeated dereferences udf: Check component length before reading it udf: Check path length when reading symlink udf: Verify symlink size before loading it udf: Verify i_size when loading inode isofs: Fix unchecked printing of ER records
Diffstat (limited to 'fs')
-rw-r--r--fs/isofs/rock.c3
-rw-r--r--fs/udf/dir.c31
-rw-r--r--fs/udf/inode.c14
-rw-r--r--fs/udf/namei.c17
-rw-r--r--fs/udf/symlink.c57
-rw-r--r--fs/udf/udfdecl.h3
-rw-r--r--fs/udf/unicode.c28
7 files changed, 106 insertions, 47 deletions
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index bb63254ed848..735d7522a3a9 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -362,6 +362,9 @@ repeat:
362 rs.cont_size = isonum_733(rr->u.CE.size); 362 rs.cont_size = isonum_733(rr->u.CE.size);
363 break; 363 break;
364 case SIG('E', 'R'): 364 case SIG('E', 'R'):
365 /* Invalid length of ER tag id? */
366 if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len)
367 goto out;
365 ISOFS_SB(inode->i_sb)->s_rock = 1; 368 ISOFS_SB(inode->i_sb)->s_rock = 1;
366 printk(KERN_DEBUG "ISO 9660 Extensions: "); 369 printk(KERN_DEBUG "ISO 9660 Extensions: ");
367 { 370 {
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index a012c51caffd..05e90edd1992 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -57,6 +57,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
57 sector_t offset; 57 sector_t offset;
58 int i, num, ret = 0; 58 int i, num, ret = 0;
59 struct extent_position epos = { NULL, 0, {0, 0} }; 59 struct extent_position epos = { NULL, 0, {0, 0} };
60 struct super_block *sb = dir->i_sb;
60 61
61 if (ctx->pos == 0) { 62 if (ctx->pos == 0) {
62 if (!dir_emit_dot(file, ctx)) 63 if (!dir_emit_dot(file, ctx))
@@ -76,16 +77,16 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
76 if (nf_pos == 0) 77 if (nf_pos == 0)
77 nf_pos = udf_ext0_offset(dir); 78 nf_pos = udf_ext0_offset(dir);
78 79
79 fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1); 80 fibh.soffset = fibh.eoffset = nf_pos & (sb->s_blocksize - 1);
80 if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 81 if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
81 if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, 82 if (inode_bmap(dir, nf_pos >> sb->s_blocksize_bits,
82 &epos, &eloc, &elen, &offset) 83 &epos, &eloc, &elen, &offset)
83 != (EXT_RECORDED_ALLOCATED >> 30)) { 84 != (EXT_RECORDED_ALLOCATED >> 30)) {
84 ret = -ENOENT; 85 ret = -ENOENT;
85 goto out; 86 goto out;
86 } 87 }
87 block = udf_get_lb_pblock(dir->i_sb, &eloc, offset); 88 block = udf_get_lb_pblock(sb, &eloc, offset);
88 if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { 89 if ((++offset << sb->s_blocksize_bits) < elen) {
89 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 90 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
90 epos.offset -= sizeof(struct short_ad); 91 epos.offset -= sizeof(struct short_ad);
91 else if (iinfo->i_alloc_type == 92 else if (iinfo->i_alloc_type ==
@@ -95,18 +96,18 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
95 offset = 0; 96 offset = 0;
96 } 97 }
97 98
98 if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) { 99 if (!(fibh.sbh = fibh.ebh = udf_tread(sb, block))) {
99 ret = -EIO; 100 ret = -EIO;
100 goto out; 101 goto out;
101 } 102 }
102 103
103 if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) { 104 if (!(offset & ((16 >> (sb->s_blocksize_bits - 9)) - 1))) {
104 i = 16 >> (dir->i_sb->s_blocksize_bits - 9); 105 i = 16 >> (sb->s_blocksize_bits - 9);
105 if (i + offset > (elen >> dir->i_sb->s_blocksize_bits)) 106 if (i + offset > (elen >> sb->s_blocksize_bits))
106 i = (elen >> dir->i_sb->s_blocksize_bits) - offset; 107 i = (elen >> sb->s_blocksize_bits) - offset;
107 for (num = 0; i > 0; i--) { 108 for (num = 0; i > 0; i--) {
108 block = udf_get_lb_pblock(dir->i_sb, &eloc, offset + i); 109 block = udf_get_lb_pblock(sb, &eloc, offset + i);
109 tmp = udf_tgetblk(dir->i_sb, block); 110 tmp = udf_tgetblk(sb, block);
110 if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) 111 if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
111 bha[num++] = tmp; 112 bha[num++] = tmp;
112 else 113 else
@@ -152,12 +153,12 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
152 } 153 }
153 154
154 if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { 155 if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
155 if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE)) 156 if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
156 continue; 157 continue;
157 } 158 }
158 159
159 if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) { 160 if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
160 if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE)) 161 if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
161 continue; 162 continue;
162 } 163 }
163 164
@@ -167,12 +168,12 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
167 continue; 168 continue;
168 } 169 }
169 170
170 flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); 171 flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN);
171 if (!flen) 172 if (!flen)
172 continue; 173 continue;
173 174
174 tloc = lelb_to_cpu(cfi.icb.extLocation); 175 tloc = lelb_to_cpu(cfi.icb.extLocation);
175 iblock = udf_get_lb_pblock(dir->i_sb, &tloc, 0); 176 iblock = udf_get_lb_pblock(sb, &tloc, 0);
176 if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN)) 177 if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN))
177 goto out; 178 goto out;
178 } /* end while */ 179 } /* end while */
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index c9b4df5810d5..5bc71d9a674a 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1489,6 +1489,20 @@ reread:
1489 } 1489 }
1490 inode->i_generation = iinfo->i_unique; 1490 inode->i_generation = iinfo->i_unique;
1491 1491
1492 /* Sanity checks for files in ICB so that we don't get confused later */
1493 if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
1494 /*
1495 * For file in ICB data is stored in allocation descriptor
1496 * so sizes should match
1497 */
1498 if (iinfo->i_lenAlloc != inode->i_size)
1499 goto out;
1500 /* File in ICB has to fit in there... */
1501 if (inode->i_size > inode->i_sb->s_blocksize -
1502 udf_file_entry_alloc_offset(inode))
1503 goto out;
1504 }
1505
1492 switch (fe->icbTag.fileType) { 1506 switch (fe->icbTag.fileType) {
1493 case ICBTAG_FILE_TYPE_DIRECTORY: 1507 case ICBTAG_FILE_TYPE_DIRECTORY:
1494 inode->i_op = &udf_dir_inode_operations; 1508 inode->i_op = &udf_dir_inode_operations;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index c12e260fd6c4..33b246b82c98 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -159,18 +159,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
159 struct udf_inode_info *dinfo = UDF_I(dir); 159 struct udf_inode_info *dinfo = UDF_I(dir);
160 int isdotdot = child->len == 2 && 160 int isdotdot = child->len == 2 &&
161 child->name[0] == '.' && child->name[1] == '.'; 161 child->name[0] == '.' && child->name[1] == '.';
162 struct super_block *sb = dir->i_sb;
162 163
163 size = udf_ext0_offset(dir) + dir->i_size; 164 size = udf_ext0_offset(dir) + dir->i_size;
164 f_pos = udf_ext0_offset(dir); 165 f_pos = udf_ext0_offset(dir);
165 166
166 fibh->sbh = fibh->ebh = NULL; 167 fibh->sbh = fibh->ebh = NULL;
167 fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); 168 fibh->soffset = fibh->eoffset = f_pos & (sb->s_blocksize - 1);
168 if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 169 if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
169 if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, 170 if (inode_bmap(dir, f_pos >> sb->s_blocksize_bits, &epos,
170 &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) 171 &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30))
171 goto out_err; 172 goto out_err;
172 block = udf_get_lb_pblock(dir->i_sb, &eloc, offset); 173 block = udf_get_lb_pblock(sb, &eloc, offset);
173 if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { 174 if ((++offset << sb->s_blocksize_bits) < elen) {
174 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) 175 if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
175 epos.offset -= sizeof(struct short_ad); 176 epos.offset -= sizeof(struct short_ad);
176 else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) 177 else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
@@ -178,7 +179,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
178 } else 179 } else
179 offset = 0; 180 offset = 0;
180 181
181 fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); 182 fibh->sbh = fibh->ebh = udf_tread(sb, block);
182 if (!fibh->sbh) 183 if (!fibh->sbh)
183 goto out_err; 184 goto out_err;
184 } 185 }
@@ -217,12 +218,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
217 } 218 }
218 219
219 if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { 220 if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
220 if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE)) 221 if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
221 continue; 222 continue;
222 } 223 }
223 224
224 if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) { 225 if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
225 if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE)) 226 if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
226 continue; 227 continue;
227 } 228 }
228 229
@@ -233,7 +234,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
233 if (!lfi) 234 if (!lfi)
234 continue; 235 continue;
235 236
236 flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); 237 flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN);
237 if (flen && udf_match(flen, fname, child->len, child->name)) 238 if (flen && udf_match(flen, fname, child->len, child->name))
238 goto out_ok; 239 goto out_ok;
239 } 240 }
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 6fb7945c1e6e..ac10ca939f26 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -30,49 +30,73 @@
30#include <linux/buffer_head.h> 30#include <linux/buffer_head.h>
31#include "udf_i.h" 31#include "udf_i.h"
32 32
33static void udf_pc_to_char(struct super_block *sb, unsigned char *from, 33static int udf_pc_to_char(struct super_block *sb, unsigned char *from,
34 int fromlen, unsigned char *to) 34 int fromlen, unsigned char *to, int tolen)
35{ 35{
36 struct pathComponent *pc; 36 struct pathComponent *pc;
37 int elen = 0; 37 int elen = 0;
38 int comp_len;
38 unsigned char *p = to; 39 unsigned char *p = to;
39 40
41 /* Reserve one byte for terminating \0 */
42 tolen--;
40 while (elen < fromlen) { 43 while (elen < fromlen) {
41 pc = (struct pathComponent *)(from + elen); 44 pc = (struct pathComponent *)(from + elen);
45 elen += sizeof(struct pathComponent);
42 switch (pc->componentType) { 46 switch (pc->componentType) {
43 case 1: 47 case 1:
44 /* 48 /*
45 * Symlink points to some place which should be agreed 49 * Symlink points to some place which should be agreed
46 * upon between originator and receiver of the media. Ignore. 50 * upon between originator and receiver of the media. Ignore.
47 */ 51 */
48 if (pc->lengthComponentIdent > 0) 52 if (pc->lengthComponentIdent > 0) {
53 elen += pc->lengthComponentIdent;
49 break; 54 break;
55 }
50 /* Fall through */ 56 /* Fall through */
51 case 2: 57 case 2:
58 if (tolen == 0)
59 return -ENAMETOOLONG;
52 p = to; 60 p = to;
53 *p++ = '/'; 61 *p++ = '/';
62 tolen--;
54 break; 63 break;
55 case 3: 64 case 3:
65 if (tolen < 3)
66 return -ENAMETOOLONG;
56 memcpy(p, "../", 3); 67 memcpy(p, "../", 3);
57 p += 3; 68 p += 3;
69 tolen -= 3;
58 break; 70 break;
59 case 4: 71 case 4:
72 if (tolen < 2)
73 return -ENAMETOOLONG;
60 memcpy(p, "./", 2); 74 memcpy(p, "./", 2);
61 p += 2; 75 p += 2;
76 tolen -= 2;
62 /* that would be . - just ignore */ 77 /* that would be . - just ignore */
63 break; 78 break;
64 case 5: 79 case 5:
65 p += udf_get_filename(sb, pc->componentIdent, p, 80 elen += pc->lengthComponentIdent;
66 pc->lengthComponentIdent); 81 if (elen > fromlen)
82 return -EIO;
83 comp_len = udf_get_filename(sb, pc->componentIdent,
84 pc->lengthComponentIdent,
85 p, tolen);
86 p += comp_len;
87 tolen -= comp_len;
88 if (tolen == 0)
89 return -ENAMETOOLONG;
67 *p++ = '/'; 90 *p++ = '/';
91 tolen--;
68 break; 92 break;
69 } 93 }
70 elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
71 } 94 }
72 if (p > to + 1) 95 if (p > to + 1)
73 p[-1] = '\0'; 96 p[-1] = '\0';
74 else 97 else
75 p[0] = '\0'; 98 p[0] = '\0';
99 return 0;
76} 100}
77 101
78static int udf_symlink_filler(struct file *file, struct page *page) 102static int udf_symlink_filler(struct file *file, struct page *page)
@@ -80,11 +104,17 @@ static int udf_symlink_filler(struct file *file, struct page *page)
80 struct inode *inode = page->mapping->host; 104 struct inode *inode = page->mapping->host;
81 struct buffer_head *bh = NULL; 105 struct buffer_head *bh = NULL;
82 unsigned char *symlink; 106 unsigned char *symlink;
83 int err = -EIO; 107 int err;
84 unsigned char *p = kmap(page); 108 unsigned char *p = kmap(page);
85 struct udf_inode_info *iinfo; 109 struct udf_inode_info *iinfo;
86 uint32_t pos; 110 uint32_t pos;
87 111
112 /* We don't support symlinks longer than one block */
113 if (inode->i_size > inode->i_sb->s_blocksize) {
114 err = -ENAMETOOLONG;
115 goto out_unmap;
116 }
117
88 iinfo = UDF_I(inode); 118 iinfo = UDF_I(inode);
89 pos = udf_block_map(inode, 0); 119 pos = udf_block_map(inode, 0);
90 120
@@ -94,14 +124,18 @@ static int udf_symlink_filler(struct file *file, struct page *page)
94 } else { 124 } else {
95 bh = sb_bread(inode->i_sb, pos); 125 bh = sb_bread(inode->i_sb, pos);
96 126
97 if (!bh) 127 if (!bh) {
98 goto out; 128 err = -EIO;
129 goto out_unlock_inode;
130 }
99 131
100 symlink = bh->b_data; 132 symlink = bh->b_data;
101 } 133 }
102 134
103 udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); 135 err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE);
104 brelse(bh); 136 brelse(bh);
137 if (err)
138 goto out_unlock_inode;
105 139
106 up_read(&iinfo->i_data_sem); 140 up_read(&iinfo->i_data_sem);
107 SetPageUptodate(page); 141 SetPageUptodate(page);
@@ -109,9 +143,10 @@ static int udf_symlink_filler(struct file *file, struct page *page)
109 unlock_page(page); 143 unlock_page(page);
110 return 0; 144 return 0;
111 145
112out: 146out_unlock_inode:
113 up_read(&iinfo->i_data_sem); 147 up_read(&iinfo->i_data_sem);
114 SetPageError(page); 148 SetPageError(page);
149out_unmap:
115 kunmap(page); 150 kunmap(page);
116 unlock_page(page); 151 unlock_page(page);
117 return err; 152 return err;
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 1cc3c993ebd0..47bb3f5ca360 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -211,7 +211,8 @@ udf_get_lb_pblock(struct super_block *sb, struct kernel_lb_addr *loc,
211} 211}
212 212
213/* unicode.c */ 213/* unicode.c */
214extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int); 214extern int udf_get_filename(struct super_block *, uint8_t *, int, uint8_t *,
215 int);
215extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, 216extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
216 int); 217 int);
217extern int udf_build_ustr(struct ustr *, dstring *, int); 218extern int udf_build_ustr(struct ustr *, dstring *, int);
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index afd470e588ff..b84fee372734 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -28,7 +28,8 @@
28 28
29#include "udf_sb.h" 29#include "udf_sb.h"
30 30
31static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int); 31static int udf_translate_to_linux(uint8_t *, int, uint8_t *, int, uint8_t *,
32 int);
32 33
33static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) 34static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
34{ 35{
@@ -333,8 +334,8 @@ try_again:
333 return u_len + 1; 334 return u_len + 1;
334} 335}
335 336
336int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, 337int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen,
337 int flen) 338 uint8_t *dname, int dlen)
338{ 339{
339 struct ustr *filename, *unifilename; 340 struct ustr *filename, *unifilename;
340 int len = 0; 341 int len = 0;
@@ -347,7 +348,7 @@ int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
347 if (!unifilename) 348 if (!unifilename)
348 goto out1; 349 goto out1;
349 350
350 if (udf_build_ustr_exact(unifilename, sname, flen)) 351 if (udf_build_ustr_exact(unifilename, sname, slen))
351 goto out2; 352 goto out2;
352 353
353 if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) { 354 if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
@@ -366,7 +367,8 @@ int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
366 } else 367 } else
367 goto out2; 368 goto out2;
368 369
369 len = udf_translate_to_linux(dname, filename->u_name, filename->u_len, 370 len = udf_translate_to_linux(dname, dlen,
371 filename->u_name, filename->u_len,
370 unifilename->u_name, unifilename->u_len); 372 unifilename->u_name, unifilename->u_len);
371out2: 373out2:
372 kfree(unifilename); 374 kfree(unifilename);
@@ -403,10 +405,12 @@ int udf_put_filename(struct super_block *sb, const uint8_t *sname,
403#define EXT_MARK '.' 405#define EXT_MARK '.'
404#define CRC_MARK '#' 406#define CRC_MARK '#'
405#define EXT_SIZE 5 407#define EXT_SIZE 5
408/* Number of chars we need to store generated CRC to make filename unique */
409#define CRC_LEN 5
406 410
407static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, 411static int udf_translate_to_linux(uint8_t *newName, int newLen,
408 int udfLen, uint8_t *fidName, 412 uint8_t *udfName, int udfLen,
409 int fidNameLen) 413 uint8_t *fidName, int fidNameLen)
410{ 414{
411 int index, newIndex = 0, needsCRC = 0; 415 int index, newIndex = 0, needsCRC = 0;
412 int extIndex = 0, newExtIndex = 0, hasExt = 0; 416 int extIndex = 0, newExtIndex = 0, hasExt = 0;
@@ -439,7 +443,7 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
439 newExtIndex = newIndex; 443 newExtIndex = newIndex;
440 } 444 }
441 } 445 }
442 if (newIndex < 256) 446 if (newIndex < newLen)
443 newName[newIndex++] = curr; 447 newName[newIndex++] = curr;
444 else 448 else
445 needsCRC = 1; 449 needsCRC = 1;
@@ -467,13 +471,13 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
467 } 471 }
468 ext[localExtIndex++] = curr; 472 ext[localExtIndex++] = curr;
469 } 473 }
470 maxFilenameLen = 250 - localExtIndex; 474 maxFilenameLen = newLen - CRC_LEN - localExtIndex;
471 if (newIndex > maxFilenameLen) 475 if (newIndex > maxFilenameLen)
472 newIndex = maxFilenameLen; 476 newIndex = maxFilenameLen;
473 else 477 else
474 newIndex = newExtIndex; 478 newIndex = newExtIndex;
475 } else if (newIndex > 250) 479 } else if (newIndex > newLen - CRC_LEN)
476 newIndex = 250; 480 newIndex = newLen - CRC_LEN;
477 newName[newIndex++] = CRC_MARK; 481 newName[newIndex++] = CRC_MARK;
478 valueCRC = crc_itu_t(0, fidName, fidNameLen); 482 valueCRC = crc_itu_t(0, fidName, fidNameLen);
479 newName[newIndex++] = hex_asc_upper_hi(valueCRC >> 8); 483 newName[newIndex++] = hex_asc_upper_hi(valueCRC >> 8);