diff options
Diffstat (limited to 'fs/isofs')
-rw-r--r-- | fs/isofs/rock.c | 237 |
1 files changed, 130 insertions, 107 deletions
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index aafe356ec1b7..efefbcce4ce9 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c | |||
@@ -22,6 +22,16 @@ | |||
22 | 22 | ||
23 | #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ | 23 | #define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */ |
24 | 24 | ||
25 | struct rock_state { | ||
26 | void *buffer; | ||
27 | unsigned char *chr; | ||
28 | int len; | ||
29 | int cont_size; | ||
30 | int cont_extent; | ||
31 | int cont_offset; | ||
32 | struct inode *inode; | ||
33 | }; | ||
34 | |||
25 | /* | 35 | /* |
26 | * This is a way of ensuring that we have something in the system | 36 | * This is a way of ensuring that we have something in the system |
27 | * use fields that is compatible with Rock Ridge. Return zero on success. | 37 | * use fields that is compatible with Rock Ridge. Return zero on success. |
@@ -38,82 +48,96 @@ static int check_sp(struct rock_ridge *rr, struct inode *inode) | |||
38 | } | 48 | } |
39 | 49 | ||
40 | static void setup_rock_ridge(struct iso_directory_record *de, | 50 | static void setup_rock_ridge(struct iso_directory_record *de, |
41 | struct inode *inode, unsigned char **chr, int *len) | 51 | struct inode *inode, struct rock_state *rs) |
42 | { | 52 | { |
43 | *len = sizeof(struct iso_directory_record) + de->name_len[0]; | 53 | rs->len = sizeof(struct iso_directory_record) + de->name_len[0]; |
44 | if (*len & 1) | 54 | if (rs->len & 1) |
45 | (*len)++; | 55 | (rs->len)++; |
46 | *chr = (unsigned char *)de + *len; | 56 | rs->chr = (unsigned char *)de + rs->len; |
47 | *len = *((unsigned char *)de) - *len; | 57 | rs->len = *((unsigned char *)de) - rs->len; |
48 | if (*len < 0) | 58 | if (rs->len < 0) |
49 | *len = 0; | 59 | rs->len = 0; |
50 | 60 | ||
51 | if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) { | 61 | if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) { |
52 | *len -= ISOFS_SB(inode->i_sb)->s_rock_offset; | 62 | rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset; |
53 | *chr += ISOFS_SB(inode->i_sb)->s_rock_offset; | 63 | rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset; |
54 | if (*len < 0) | 64 | if (rs->len < 0) |
55 | *len = 0; | 65 | rs->len = 0; |
56 | } | 66 | } |
57 | } | 67 | } |
58 | 68 | ||
59 | #define MAYBE_CONTINUE(LABEL,DEV) \ | 69 | static void init_rock_state(struct rock_state *rs, struct inode *inode) |
60 | {if (buffer) { kfree(buffer); buffer = NULL; } \ | 70 | { |
61 | if (cont_extent){ \ | 71 | memset(rs, 0, sizeof(*rs)); |
62 | int block, offset, offset1; \ | 72 | rs->inode = inode; |
63 | struct buffer_head * pbh; \ | 73 | } |
64 | buffer = kmalloc(cont_size,GFP_KERNEL); \ | 74 | |
65 | if (!buffer) goto out; \ | 75 | /* |
66 | block = cont_extent; \ | 76 | * Returns 0 if the caller should continue scanning, 1 if the scan must end |
67 | offset = cont_offset; \ | 77 | * and -ve on error. |
68 | offset1 = 0; \ | 78 | */ |
69 | pbh = sb_bread(DEV->i_sb, block); \ | 79 | static int rock_continue(struct rock_state *rs) |
70 | if(pbh){ \ | 80 | { |
71 | if (offset > pbh->b_size || offset + cont_size > pbh->b_size){ \ | 81 | int ret = 1; |
72 | brelse(pbh); \ | 82 | |
73 | goto out; \ | 83 | kfree(rs->buffer); |
74 | } \ | 84 | rs->buffer = NULL; |
75 | memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \ | 85 | if (rs->cont_extent) { |
76 | brelse(pbh); \ | 86 | struct buffer_head *bh; |
77 | chr = (unsigned char *) buffer; \ | 87 | |
78 | len = cont_size; \ | 88 | rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL); |
79 | cont_extent = 0; \ | 89 | if (!rs->buffer) { |
80 | cont_size = 0; \ | 90 | ret = -ENOMEM; |
81 | cont_offset = 0; \ | 91 | goto out; |
82 | goto LABEL; \ | 92 | } |
83 | } \ | 93 | ret = -EIO; |
84 | printk("Unable to read rock-ridge attributes\n"); \ | 94 | bh = sb_bread(rs->inode->i_sb, rs->cont_extent); |
85 | }} | 95 | if (bh) { |
96 | memcpy(rs->buffer, bh->b_data + rs->cont_offset, | ||
97 | rs->cont_size); | ||
98 | put_bh(bh); | ||
99 | rs->chr = rs->buffer; | ||
100 | rs->len = rs->cont_size; | ||
101 | rs->cont_extent = 0; | ||
102 | rs->cont_size = 0; | ||
103 | rs->cont_offset = 0; | ||
104 | return 0; | ||
105 | } | ||
106 | printk("Unable to read rock-ridge attributes\n"); | ||
107 | } | ||
108 | out: | ||
109 | kfree(rs->buffer); | ||
110 | rs->buffer = NULL; | ||
111 | return ret; | ||
112 | } | ||
86 | 113 | ||
87 | /* return length of name field; 0: not found, -1: to be ignored */ | 114 | /* return length of name field; 0: not found, -1: to be ignored */ |
88 | int get_rock_ridge_filename(struct iso_directory_record *de, | 115 | int get_rock_ridge_filename(struct iso_directory_record *de, |
89 | char *retname, struct inode *inode) | 116 | char *retname, struct inode *inode) |
90 | { | 117 | { |
91 | int len; | 118 | struct rock_state rs; |
92 | unsigned char *chr; | ||
93 | int cont_extent = 0; | ||
94 | int cont_offset = 0; | ||
95 | int cont_size = 0; | ||
96 | void *buffer = NULL; | ||
97 | struct rock_ridge *rr; | 119 | struct rock_ridge *rr; |
98 | int sig; | 120 | int sig; |
99 | int retnamlen = 0; | 121 | int retnamlen = 0; |
100 | int truncate = 0; | 122 | int truncate = 0; |
123 | int ret = 0; | ||
101 | 124 | ||
102 | if (!ISOFS_SB(inode->i_sb)->s_rock) | 125 | if (!ISOFS_SB(inode->i_sb)->s_rock) |
103 | return 0; | 126 | return 0; |
104 | *retname = 0; | 127 | *retname = 0; |
105 | 128 | ||
106 | setup_rock_ridge(de, inode, &chr, &len); | 129 | init_rock_state(&rs, inode); |
130 | setup_rock_ridge(de, inode, &rs); | ||
107 | repeat: | 131 | repeat: |
108 | 132 | ||
109 | while (len > 2) { /* There may be one byte for padding somewhere */ | 133 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ |
110 | rr = (struct rock_ridge *)chr; | 134 | rr = (struct rock_ridge *)rs.chr; |
111 | if (rr->len < 3) | 135 | if (rr->len < 3) |
112 | goto out; /* Something got screwed up here */ | 136 | goto out; /* Something got screwed up here */ |
113 | sig = isonum_721(chr); | 137 | sig = isonum_721(rs.chr); |
114 | chr += rr->len; | 138 | rs.chr += rr->len; |
115 | len -= rr->len; | 139 | rs.len -= rr->len; |
116 | if (len < 0) | 140 | if (rs.len < 0) |
117 | goto out; /* corrupted isofs */ | 141 | goto out; /* corrupted isofs */ |
118 | 142 | ||
119 | switch (sig) { | 143 | switch (sig) { |
@@ -126,9 +150,9 @@ repeat: | |||
126 | goto out; | 150 | goto out; |
127 | break; | 151 | break; |
128 | case SIG('C', 'E'): | 152 | case SIG('C', 'E'): |
129 | cont_extent = isonum_733(rr->u.CE.extent); | 153 | rs.cont_extent = isonum_733(rr->u.CE.extent); |
130 | cont_offset = isonum_733(rr->u.CE.offset); | 154 | rs.cont_offset = isonum_733(rr->u.CE.offset); |
131 | cont_size = isonum_733(rr->u.CE.size); | 155 | rs.cont_size = isonum_733(rr->u.CE.size); |
132 | break; | 156 | break; |
133 | case SIG('N', 'M'): | 157 | case SIG('N', 'M'): |
134 | if (truncate) | 158 | if (truncate) |
@@ -158,58 +182,55 @@ repeat: | |||
158 | retnamlen += rr->len - 5; | 182 | retnamlen += rr->len - 5; |
159 | break; | 183 | break; |
160 | case SIG('R', 'E'): | 184 | case SIG('R', 'E'): |
161 | if (buffer) | 185 | kfree(rs.buffer); |
162 | kfree(buffer); | ||
163 | return -1; | 186 | return -1; |
164 | default: | 187 | default: |
165 | break; | 188 | break; |
166 | } | 189 | } |
167 | } | 190 | } |
168 | MAYBE_CONTINUE(repeat, inode); | 191 | ret = rock_continue(&rs); |
169 | kfree(buffer); | 192 | if (ret == 0) |
170 | return retnamlen; /* If 0, this file did not have a NM field */ | 193 | goto repeat; |
194 | if (ret == 1) | ||
195 | return retnamlen; /* If 0, this file did not have a NM field */ | ||
171 | out: | 196 | out: |
172 | if (buffer) | 197 | kfree(rs.buffer); |
173 | kfree(buffer); | 198 | return ret; |
174 | return 0; | ||
175 | } | 199 | } |
176 | 200 | ||
177 | static int | 201 | static int |
178 | parse_rock_ridge_inode_internal(struct iso_directory_record *de, | 202 | parse_rock_ridge_inode_internal(struct iso_directory_record *de, |
179 | struct inode *inode, int regard_xa) | 203 | struct inode *inode, int regard_xa) |
180 | { | 204 | { |
181 | int len; | ||
182 | unsigned char *chr; | ||
183 | int symlink_len = 0; | 205 | int symlink_len = 0; |
184 | int cnt, sig; | 206 | int cnt, sig; |
185 | struct inode *reloc; | 207 | struct inode *reloc; |
186 | struct rock_ridge *rr; | 208 | struct rock_ridge *rr; |
187 | int rootflag; | 209 | int rootflag; |
188 | int cont_extent = 0; | 210 | struct rock_state rs; |
189 | int cont_offset = 0; | 211 | int ret = 0; |
190 | int cont_size = 0; | ||
191 | void *buffer = NULL; | ||
192 | 212 | ||
193 | if (!ISOFS_SB(inode->i_sb)->s_rock) | 213 | if (!ISOFS_SB(inode->i_sb)->s_rock) |
194 | return 0; | 214 | return 0; |
195 | 215 | ||
196 | setup_rock_ridge(de, inode, &chr, &len); | 216 | init_rock_state(&rs, inode); |
217 | setup_rock_ridge(de, inode, &rs); | ||
197 | if (regard_xa) { | 218 | if (regard_xa) { |
198 | chr += 14; | 219 | rs.chr += 14; |
199 | len -= 14; | 220 | rs.len -= 14; |
200 | if (len < 0) | 221 | if (rs.len < 0) |
201 | len = 0; | 222 | rs.len = 0; |
202 | } | 223 | } |
203 | 224 | ||
204 | repeat: | 225 | repeat: |
205 | while (len > 2) { /* There may be one byte for padding somewhere */ | 226 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ |
206 | rr = (struct rock_ridge *)chr; | 227 | rr = (struct rock_ridge *)rs.chr; |
207 | if (rr->len < 3) | 228 | if (rr->len < 3) |
208 | goto out; /* Something got screwed up here */ | 229 | goto out; /* Something got screwed up here */ |
209 | sig = isonum_721(chr); | 230 | sig = isonum_721(rs.chr); |
210 | chr += rr->len; | 231 | rs.chr += rr->len; |
211 | len -= rr->len; | 232 | rs.len -= rr->len; |
212 | if (len < 0) | 233 | if (rs.len < 0) |
213 | goto out; /* corrupted isofs */ | 234 | goto out; /* corrupted isofs */ |
214 | 235 | ||
215 | switch (sig) { | 236 | switch (sig) { |
@@ -225,9 +246,9 @@ repeat: | |||
225 | goto out; | 246 | goto out; |
226 | break; | 247 | break; |
227 | case SIG('C', 'E'): | 248 | case SIG('C', 'E'): |
228 | cont_extent = isonum_733(rr->u.CE.extent); | 249 | rs.cont_extent = isonum_733(rr->u.CE.extent); |
229 | cont_offset = isonum_733(rr->u.CE.offset); | 250 | rs.cont_offset = isonum_733(rr->u.CE.offset); |
230 | cont_size = isonum_733(rr->u.CE.size); | 251 | rs.cont_size = isonum_733(rr->u.CE.size); |
231 | break; | 252 | break; |
232 | case SIG('E', 'R'): | 253 | case SIG('E', 'R'): |
233 | ISOFS_SB(inode->i_sb)->s_rock = 1; | 254 | ISOFS_SB(inode->i_sb)->s_rock = 1; |
@@ -433,11 +454,14 @@ repeat: | |||
433 | break; | 454 | break; |
434 | } | 455 | } |
435 | } | 456 | } |
436 | MAYBE_CONTINUE(repeat, inode); | 457 | ret = rock_continue(&rs); |
458 | if (ret == 0) | ||
459 | goto repeat; | ||
460 | if (ret == 1) | ||
461 | ret = 0; | ||
437 | out: | 462 | out: |
438 | if (buffer) | 463 | kfree(rs.buffer); |
439 | kfree(buffer); | 464 | return ret; |
440 | return 0; | ||
441 | } | 465 | } |
442 | 466 | ||
443 | static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) | 467 | static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit) |
@@ -533,19 +557,16 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) | |||
533 | char *rpnt = link; | 557 | char *rpnt = link; |
534 | unsigned char *pnt; | 558 | unsigned char *pnt; |
535 | struct iso_directory_record *raw_de; | 559 | struct iso_directory_record *raw_de; |
536 | int cont_extent = 0; | ||
537 | int cont_offset = 0; | ||
538 | int cont_size = 0; | ||
539 | void *buffer = NULL; | ||
540 | unsigned long block, offset; | 560 | unsigned long block, offset; |
541 | int sig; | 561 | int sig; |
542 | int len; | ||
543 | unsigned char *chr; | ||
544 | struct rock_ridge *rr; | 562 | struct rock_ridge *rr; |
563 | struct rock_state rs; | ||
564 | int ret; | ||
545 | 565 | ||
546 | if (!ISOFS_SB(inode->i_sb)->s_rock) | 566 | if (!ISOFS_SB(inode->i_sb)->s_rock) |
547 | goto error; | 567 | goto error; |
548 | 568 | ||
569 | init_rock_state(&rs, inode); | ||
549 | block = ei->i_iget5_block; | 570 | block = ei->i_iget5_block; |
550 | lock_kernel(); | 571 | lock_kernel(); |
551 | bh = sb_bread(inode->i_sb, block); | 572 | bh = sb_bread(inode->i_sb, block); |
@@ -566,17 +587,17 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) | |||
566 | /* Now test for possible Rock Ridge extensions which will override | 587 | /* Now test for possible Rock Ridge extensions which will override |
567 | some of these numbers in the inode structure. */ | 588 | some of these numbers in the inode structure. */ |
568 | 589 | ||
569 | setup_rock_ridge(raw_de, inode, &chr, &len); | 590 | setup_rock_ridge(raw_de, inode, &rs); |
570 | 591 | ||
571 | repeat: | 592 | repeat: |
572 | while (len > 2) { /* There may be one byte for padding somewhere */ | 593 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ |
573 | rr = (struct rock_ridge *)chr; | 594 | rr = (struct rock_ridge *)rs.chr; |
574 | if (rr->len < 3) | 595 | if (rr->len < 3) |
575 | goto out; /* Something got screwed up here */ | 596 | goto out; /* Something got screwed up here */ |
576 | sig = isonum_721(chr); | 597 | sig = isonum_721(rs.chr); |
577 | chr += rr->len; | 598 | rs.chr += rr->len; |
578 | len -= rr->len; | 599 | rs.len -= rr->len; |
579 | if (len < 0) | 600 | if (rs.len < 0) |
580 | goto out; /* corrupted isofs */ | 601 | goto out; /* corrupted isofs */ |
581 | 602 | ||
582 | switch (sig) { | 603 | switch (sig) { |
@@ -596,15 +617,18 @@ repeat: | |||
596 | break; | 617 | break; |
597 | case SIG('C', 'E'): | 618 | case SIG('C', 'E'): |
598 | /* This tells is if there is a continuation record */ | 619 | /* This tells is if there is a continuation record */ |
599 | cont_extent = isonum_733(rr->u.CE.extent); | 620 | rs.cont_extent = isonum_733(rr->u.CE.extent); |
600 | cont_offset = isonum_733(rr->u.CE.offset); | 621 | rs.cont_offset = isonum_733(rr->u.CE.offset); |
601 | cont_size = isonum_733(rr->u.CE.size); | 622 | rs.cont_size = isonum_733(rr->u.CE.size); |
602 | default: | 623 | default: |
603 | break; | 624 | break; |
604 | } | 625 | } |
605 | } | 626 | } |
606 | MAYBE_CONTINUE(repeat, inode); | 627 | ret = rock_continue(&rs); |
607 | kfree(buffer); | 628 | if (ret == 0) |
629 | goto repeat; | ||
630 | if (ret < 0) | ||
631 | goto fail; | ||
608 | 632 | ||
609 | if (rpnt == link) | 633 | if (rpnt == link) |
610 | goto fail; | 634 | goto fail; |
@@ -618,8 +642,7 @@ repeat: | |||
618 | 642 | ||
619 | /* error exit from macro */ | 643 | /* error exit from macro */ |
620 | out: | 644 | out: |
621 | if (buffer) | 645 | kfree(rs.buffer); |
622 | kfree(buffer); | ||
623 | goto fail; | 646 | goto fail; |
624 | out_noread: | 647 | out_noread: |
625 | printk("unable to read i-node block"); | 648 | printk("unable to read i-node block"); |