blob: 283e92197bb17fe0e323e61ee7f041d23116223f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/isofs/rock.c
3 *
4 * (C) 1992, 1993 Eric Youngdale
5 *
6 * Rock Ridge Extensions to iso9660
7 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/slab.h>
10#include <linux/pagemap.h>
11#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Al Viro94f2f712005-04-25 18:32:12 -070013#include "isofs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include "rock.h"
15
16/* These functions are designed to read the system areas of a directory record
17 * and extract relevant information. There are different functions provided
18 * depending upon what information we need at the time. One function fills
19 * out an inode structure, a second one extracts a filename, a third one
20 * returns a symbolic link name, and a fourth one returns the extent number
21 * for the file. */
22
Andrew Morton1d372112005-06-21 17:16:42 -070023#define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Andrew Morton12121712005-06-21 17:16:44 -070025/*
26 * 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.
28 */
29
30static int check_sp(struct rock_ridge *rr, struct inode *inode)
31{
32 if (rr->u.SP.magic[0] != 0xbe)
33 return -1;
34 if (rr->u.SP.magic[1] != 0xef)
35 return -1;
36 ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip;
37 return 0;
38}
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \
41 {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \
42 if(LEN & 1) LEN++; \
43 CHR = ((unsigned char *) DE) + LEN; \
44 LEN = *((unsigned char *) DE) - LEN; \
45 if (LEN<0) LEN=0; \
46 if (ISOFS_SB(inode->i_sb)->s_rock_offset!=-1) \
47 { \
48 LEN-=ISOFS_SB(inode->i_sb)->s_rock_offset; \
49 CHR+=ISOFS_SB(inode->i_sb)->s_rock_offset; \
50 if (LEN<0) LEN=0; \
51 } \
Andrew Morton1d372112005-06-21 17:16:42 -070052}
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54#define MAYBE_CONTINUE(LABEL,DEV) \
55 {if (buffer) { kfree(buffer); buffer = NULL; } \
56 if (cont_extent){ \
57 int block, offset, offset1; \
58 struct buffer_head * pbh; \
59 buffer = kmalloc(cont_size,GFP_KERNEL); \
60 if (!buffer) goto out; \
61 block = cont_extent; \
62 offset = cont_offset; \
63 offset1 = 0; \
64 pbh = sb_bread(DEV->i_sb, block); \
65 if(pbh){ \
66 if (offset > pbh->b_size || offset + cont_size > pbh->b_size){ \
67 brelse(pbh); \
68 goto out; \
69 } \
70 memcpy(buffer + offset1, pbh->b_data + offset, cont_size - offset1); \
71 brelse(pbh); \
72 chr = (unsigned char *) buffer; \
73 len = cont_size; \
74 cont_extent = 0; \
75 cont_size = 0; \
76 cont_offset = 0; \
77 goto LABEL; \
78 } \
79 printk("Unable to read rock-ridge attributes\n"); \
80 }}
81
82/* return length of name field; 0: not found, -1: to be ignored */
Andrew Morton1d372112005-06-21 17:16:42 -070083int get_rock_ridge_filename(struct iso_directory_record *de,
84 char *retname, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -070085{
Andrew Morton1d372112005-06-21 17:16:42 -070086 int len;
87 unsigned char *chr;
Andrew Mortona40ea8f2005-06-21 17:16:44 -070088 int cont_extent = 0;
89 int cont_offset = 0;
90 int cont_size = 0;
91 void *buffer = NULL;
Andrew Morton7fa393a2005-06-21 17:16:43 -070092 struct rock_ridge *rr;
93 int sig;
94 int retnamlen = 0;
95 int truncate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Andrew Morton1d372112005-06-21 17:16:42 -070097 if (!ISOFS_SB(inode->i_sb)->s_rock)
98 return 0;
99 *retname = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Andrew Morton1d372112005-06-21 17:16:42 -0700101 SETUP_ROCK_RIDGE(de, chr, len);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700102repeat:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Andrew Morton7fa393a2005-06-21 17:16:43 -0700104 while (len > 2) { /* There may be one byte for padding somewhere */
105 rr = (struct rock_ridge *)chr;
106 if (rr->len < 3)
107 goto out; /* Something got screwed up here */
108 sig = isonum_721(chr);
109 chr += rr->len;
110 len -= rr->len;
111 if (len < 0)
112 goto out; /* corrupted isofs */
Andrew Morton1d372112005-06-21 17:16:42 -0700113
Andrew Morton7fa393a2005-06-21 17:16:43 -0700114 switch (sig) {
115 case SIG('R', 'R'):
116 if ((rr->u.RR.flags[0] & RR_NM) == 0)
117 goto out;
118 break;
119 case SIG('S', 'P'):
Andrew Morton12121712005-06-21 17:16:44 -0700120 if (check_sp(rr, inode))
121 goto out;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700122 break;
123 case SIG('C', 'E'):
Andrew Morton04f7aa92005-06-21 17:16:45 -0700124 cont_extent = isonum_733(rr->u.CE.extent);
125 cont_offset = isonum_733(rr->u.CE.offset);
126 cont_size = isonum_733(rr->u.CE.size);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700127 break;
128 case SIG('N', 'M'):
129 if (truncate)
Andrew Morton1d372112005-06-21 17:16:42 -0700130 break;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700131 if (rr->len < 5)
Andrew Morton1d372112005-06-21 17:16:42 -0700132 break;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700133 /*
134 * If the flags are 2 or 4, this indicates '.' or '..'.
135 * We don't want to do anything with this, because it
136 * screws up the code that calls us. We don't really
137 * care anyways, since we can just use the non-RR
138 * name.
139 */
140 if (rr->u.NM.flags & 6)
Andrew Morton1d372112005-06-21 17:16:42 -0700141 break;
Andrew Morton1d372112005-06-21 17:16:42 -0700142
Andrew Morton7fa393a2005-06-21 17:16:43 -0700143 if (rr->u.NM.flags & ~1) {
144 printk("Unsupported NM flag settings (%d)\n",
145 rr->u.NM.flags);
Andrew Morton1d372112005-06-21 17:16:42 -0700146 break;
147 }
Andrew Morton7fa393a2005-06-21 17:16:43 -0700148 if ((strlen(retname) + rr->len - 5) >= 254) {
149 truncate = 1;
150 break;
151 }
152 strncat(retname, rr->u.NM.name, rr->len - 5);
153 retnamlen += rr->len - 5;
154 break;
155 case SIG('R', 'E'):
156 if (buffer)
157 kfree(buffer);
158 return -1;
159 default:
160 break;
Andrew Morton1d372112005-06-21 17:16:42 -0700161 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 }
Andrew Morton1d372112005-06-21 17:16:42 -0700163 MAYBE_CONTINUE(repeat, inode);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700164 kfree(buffer);
Andrew Morton1d372112005-06-21 17:16:42 -0700165 return retnamlen; /* If 0, this file did not have a NM field */
Andrew Morton7fa393a2005-06-21 17:16:43 -0700166out:
Andrew Morton1d372112005-06-21 17:16:42 -0700167 if (buffer)
168 kfree(buffer);
169 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170}
171
172static int
173parse_rock_ridge_inode_internal(struct iso_directory_record *de,
174 struct inode *inode, int regard_xa)
175{
Andrew Morton1d372112005-06-21 17:16:42 -0700176 int len;
177 unsigned char *chr;
178 int symlink_len = 0;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700179 int cnt, sig;
180 struct inode *reloc;
181 struct rock_ridge *rr;
182 int rootflag;
Andrew Mortona40ea8f2005-06-21 17:16:44 -0700183 int cont_extent = 0;
184 int cont_offset = 0;
185 int cont_size = 0;
186 void *buffer = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Andrew Morton1d372112005-06-21 17:16:42 -0700188 if (!ISOFS_SB(inode->i_sb)->s_rock)
189 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Andrew Morton1d372112005-06-21 17:16:42 -0700191 SETUP_ROCK_RIDGE(de, chr, len);
192 if (regard_xa) {
193 chr += 14;
194 len -= 14;
195 if (len < 0)
196 len = 0;
197 }
198
Andrew Morton7fa393a2005-06-21 17:16:43 -0700199repeat:
200 while (len > 2) { /* There may be one byte for padding somewhere */
201 rr = (struct rock_ridge *)chr;
202 if (rr->len < 3)
203 goto out; /* Something got screwed up here */
204 sig = isonum_721(chr);
205 chr += rr->len;
206 len -= rr->len;
207 if (len < 0)
208 goto out; /* corrupted isofs */
Andrew Morton1d372112005-06-21 17:16:42 -0700209
Andrew Morton7fa393a2005-06-21 17:16:43 -0700210 switch (sig) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211#ifndef CONFIG_ZISOFS /* No flag for SF or ZF */
Andrew Morton7fa393a2005-06-21 17:16:43 -0700212 case SIG('R', 'R'):
213 if ((rr->u.RR.flags[0] &
214 (RR_PX | RR_TF | RR_SL | RR_CL)) == 0)
Andrew Morton1d372112005-06-21 17:16:42 -0700215 goto out;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700216 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217#endif
Andrew Morton7fa393a2005-06-21 17:16:43 -0700218 case SIG('S', 'P'):
Andrew Morton12121712005-06-21 17:16:44 -0700219 if (check_sp(rr, inode))
220 goto out;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700221 break;
222 case SIG('C', 'E'):
Andrew Morton04f7aa92005-06-21 17:16:45 -0700223 cont_extent = isonum_733(rr->u.CE.extent);
224 cont_offset = isonum_733(rr->u.CE.offset);
225 cont_size = isonum_733(rr->u.CE.size);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700226 break;
227 case SIG('E', 'R'):
228 ISOFS_SB(inode->i_sb)->s_rock = 1;
229 printk(KERN_DEBUG "ISO 9660 Extensions: ");
230 {
231 int p;
232 for (p = 0; p < rr->u.ER.len_id; p++)
233 printk("%c", rr->u.ER.data[p]);
Andrew Morton1d372112005-06-21 17:16:42 -0700234 }
Andrew Morton7fa393a2005-06-21 17:16:43 -0700235 printk("\n");
236 break;
237 case SIG('P', 'X'):
238 inode->i_mode = isonum_733(rr->u.PX.mode);
239 inode->i_nlink = isonum_733(rr->u.PX.n_links);
240 inode->i_uid = isonum_733(rr->u.PX.uid);
241 inode->i_gid = isonum_733(rr->u.PX.gid);
242 break;
243 case SIG('P', 'N'):
244 {
245 int high, low;
246 high = isonum_733(rr->u.PN.dev_high);
247 low = isonum_733(rr->u.PN.dev_low);
248 /*
249 * The Rock Ridge standard specifies that if
250 * sizeof(dev_t) <= 4, then the high field is
251 * unused, and the device number is completely
252 * stored in the low field. Some writers may
253 * ignore this subtlety,
254 * and as a result we test to see if the entire
255 * device number is
256 * stored in the low field, and use that.
257 */
258 if ((low & ~0xff) && high == 0) {
259 inode->i_rdev =
260 MKDEV(low >> 8, low & 0xff);
261 } else {
262 inode->i_rdev =
263 MKDEV(high, low);
264 }
265 }
266 break;
267 case SIG('T', 'F'):
268 /*
269 * Some RRIP writers incorrectly place ctime in the
270 * TF_CREATE field. Try to handle this correctly for
271 * either case.
272 */
273 /* Rock ridge never appears on a High Sierra disk */
274 cnt = 0;
275 if (rr->u.TF.flags & TF_CREATE) {
276 inode->i_ctime.tv_sec =
277 iso_date(rr->u.TF.times[cnt++].time,
278 0);
279 inode->i_ctime.tv_nsec = 0;
280 }
281 if (rr->u.TF.flags & TF_MODIFY) {
282 inode->i_mtime.tv_sec =
283 iso_date(rr->u.TF.times[cnt++].time,
284 0);
285 inode->i_mtime.tv_nsec = 0;
286 }
287 if (rr->u.TF.flags & TF_ACCESS) {
288 inode->i_atime.tv_sec =
289 iso_date(rr->u.TF.times[cnt++].time,
290 0);
291 inode->i_atime.tv_nsec = 0;
292 }
293 if (rr->u.TF.flags & TF_ATTRIBUTES) {
294 inode->i_ctime.tv_sec =
295 iso_date(rr->u.TF.times[cnt++].time,
296 0);
297 inode->i_ctime.tv_nsec = 0;
298 }
299 break;
300 case SIG('S', 'L'):
301 {
302 int slen;
303 struct SL_component *slp;
304 struct SL_component *oldslp;
305 slen = rr->len - 5;
306 slp = &rr->u.SL.link;
307 inode->i_size = symlink_len;
308 while (slen > 1) {
309 rootflag = 0;
310 switch (slp->flags & ~1) {
311 case 0:
312 inode->i_size +=
313 slp->len;
314 break;
315 case 2:
316 inode->i_size += 1;
317 break;
318 case 4:
319 inode->i_size += 2;
320 break;
321 case 8:
322 rootflag = 1;
323 inode->i_size += 1;
324 break;
325 default:
326 printk("Symlink component flag "
327 "not implemented\n");
328 }
329 slen -= slp->len + 2;
330 oldslp = slp;
331 slp = (struct SL_component *)
332 (((char *)slp) + slp->len + 2);
333
334 if (slen < 2) {
335 if (((rr->u.SL.
336 flags & 1) != 0)
337 &&
338 ((oldslp->
339 flags & 1) == 0))
340 inode->i_size +=
341 1;
342 break;
343 }
344
345 /*
346 * If this component record isn't
347 * continued, then append a '/'.
348 */
349 if (!rootflag
350 && (oldslp->flags & 1) == 0)
351 inode->i_size += 1;
352 }
353 }
354 symlink_len = inode->i_size;
355 break;
356 case SIG('R', 'E'):
357 printk(KERN_WARNING "Attempt to read inode for "
358 "relocated directory\n");
359 goto out;
360 case SIG('C', 'L'):
361 ISOFS_I(inode)->i_first_extent =
362 isonum_733(rr->u.CL.location);
363 reloc =
364 isofs_iget(inode->i_sb,
365 ISOFS_I(inode)->i_first_extent,
366 0);
367 if (!reloc)
368 goto out;
369 inode->i_mode = reloc->i_mode;
370 inode->i_nlink = reloc->i_nlink;
371 inode->i_uid = reloc->i_uid;
372 inode->i_gid = reloc->i_gid;
373 inode->i_rdev = reloc->i_rdev;
374 inode->i_size = reloc->i_size;
375 inode->i_blocks = reloc->i_blocks;
376 inode->i_atime = reloc->i_atime;
377 inode->i_ctime = reloc->i_ctime;
378 inode->i_mtime = reloc->i_mtime;
379 iput(reloc);
380 break;
381#ifdef CONFIG_ZISOFS
382 case SIG('Z', 'F'): {
383 int algo;
384
385 if (ISOFS_SB(inode->i_sb)->s_nocompress)
386 break;
387 algo = isonum_721(rr->u.ZF.algorithm);
388 if (algo == SIG('p', 'z')) {
389 int block_shift =
390 isonum_711(&rr->u.ZF.parms[1]);
391 if (block_shift < PAGE_CACHE_SHIFT
392 || block_shift > 17) {
393 printk(KERN_WARNING "isofs: "
394 "Can't handle ZF block "
395 "size of 2^%d\n",
396 block_shift);
397 } else {
398 /*
399 * Note: we don't change
400 * i_blocks here
401 */
402 ISOFS_I(inode)->i_file_format =
403 isofs_file_compressed;
404 /*
405 * Parameters to compression
406 * algorithm (header size,
407 * block size)
408 */
409 ISOFS_I(inode)->i_format_parm[0] =
410 isonum_711(&rr->u.ZF.parms[0]);
411 ISOFS_I(inode)->i_format_parm[1] =
412 isonum_711(&rr->u.ZF.parms[1]);
413 inode->i_size =
414 isonum_733(rr->u.ZF.
415 real_size);
416 }
417 } else {
418 printk(KERN_WARNING
419 "isofs: Unknown ZF compression "
420 "algorithm: %c%c\n",
421 rr->u.ZF.algorithm[0],
422 rr->u.ZF.algorithm[1]);
423 }
424 break;
425 }
426#endif
427 default:
428 break;
Andrew Morton1d372112005-06-21 17:16:42 -0700429 }
430 }
431 MAYBE_CONTINUE(repeat, inode);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700432out:
Andrew Morton1d372112005-06-21 17:16:42 -0700433 if (buffer)
434 kfree(buffer);
435 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436}
437
438static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
439{
440 int slen;
441 int rootflag;
442 struct SL_component *oldslp;
443 struct SL_component *slp;
444 slen = rr->len - 5;
445 slp = &rr->u.SL.link;
446 while (slen > 1) {
447 rootflag = 0;
448 switch (slp->flags & ~1) {
449 case 0:
450 if (slp->len > plimit - rpnt)
451 return NULL;
452 memcpy(rpnt, slp->text, slp->len);
Andrew Morton1d372112005-06-21 17:16:42 -0700453 rpnt += slp->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 break;
455 case 2:
456 if (rpnt >= plimit)
457 return NULL;
Andrew Morton1d372112005-06-21 17:16:42 -0700458 *rpnt++ = '.';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 break;
460 case 4:
461 if (2 > plimit - rpnt)
462 return NULL;
Andrew Morton1d372112005-06-21 17:16:42 -0700463 *rpnt++ = '.';
464 *rpnt++ = '.';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 break;
466 case 8:
467 if (rpnt >= plimit)
468 return NULL;
469 rootflag = 1;
Andrew Morton1d372112005-06-21 17:16:42 -0700470 *rpnt++ = '/';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 break;
472 default:
473 printk("Symlink component flag not implemented (%d)\n",
Andrew Morton1d372112005-06-21 17:16:42 -0700474 slp->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 }
476 slen -= slp->len + 2;
477 oldslp = slp;
Andrew Morton1d372112005-06-21 17:16:42 -0700478 slp = (struct SL_component *)((char *)slp + slp->len + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
480 if (slen < 2) {
481 /*
482 * If there is another SL record, and this component
483 * record isn't continued, then add a slash.
484 */
485 if ((!rootflag) && (rr->u.SL.flags & 1) &&
486 !(oldslp->flags & 1)) {
487 if (rpnt >= plimit)
488 return NULL;
Andrew Morton1d372112005-06-21 17:16:42 -0700489 *rpnt++ = '/';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 }
491 break;
492 }
493
494 /*
495 * If this component record isn't continued, then append a '/'.
496 */
497 if (!rootflag && !(oldslp->flags & 1)) {
498 if (rpnt >= plimit)
499 return NULL;
Andrew Morton1d372112005-06-21 17:16:42 -0700500 *rpnt++ = '/';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
502 }
503 return rpnt;
504}
505
Andrew Morton1d372112005-06-21 17:16:42 -0700506int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
Andrew Morton1d372112005-06-21 17:16:42 -0700508 int result = parse_rock_ridge_inode_internal(de, inode, 0);
509 /* if rockridge flag was reset and we didn't look for attributes
510 * behind eventual XA attributes, have a look there */
511 if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1)
512 && (ISOFS_SB(inode->i_sb)->s_rock == 2)) {
513 result = parse_rock_ridge_inode_internal(de, inode, 14);
514 }
515 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516}
517
518/* readpage() for symlinks: reads symlink contents into the page and either
519 makes it uptodate and returns 0 or returns error (-EIO) */
520
521static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
522{
523 struct inode *inode = page->mapping->host;
Andrew Morton1d372112005-06-21 17:16:42 -0700524 struct iso_inode_info *ei = ISOFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 char *link = kmap(page);
526 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
527 struct buffer_head *bh;
528 char *rpnt = link;
529 unsigned char *pnt;
530 struct iso_directory_record *raw_inode;
Andrew Mortona40ea8f2005-06-21 17:16:44 -0700531 int cont_extent = 0;
532 int cont_offset = 0;
533 int cont_size = 0;
534 void *buffer = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 unsigned long block, offset;
536 int sig;
537 int len;
538 unsigned char *chr;
539 struct rock_ridge *rr;
540
541 if (!ISOFS_SB(inode->i_sb)->s_rock)
542 goto error;
543
544 block = ei->i_iget5_block;
545 lock_kernel();
546 bh = sb_bread(inode->i_sb, block);
547 if (!bh)
548 goto out_noread;
549
Andrew Morton1d372112005-06-21 17:16:42 -0700550 offset = ei->i_iget5_offset;
551 pnt = (unsigned char *)bh->b_data + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Andrew Morton1d372112005-06-21 17:16:42 -0700553 raw_inode = (struct iso_directory_record *)pnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 /*
556 * If we go past the end of the buffer, there is some sort of error.
557 */
558 if (offset + *pnt > bufsize)
559 goto out_bad_span;
560
561 /* Now test for possible Rock Ridge extensions which will override
562 some of these numbers in the inode structure. */
563
564 SETUP_ROCK_RIDGE(raw_inode, chr, len);
565
Andrew Morton7fa393a2005-06-21 17:16:43 -0700566repeat:
567 while (len > 2) { /* There may be one byte for padding somewhere */
Andrew Morton1d372112005-06-21 17:16:42 -0700568 rr = (struct rock_ridge *)chr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (rr->len < 3)
570 goto out; /* Something got screwed up here */
571 sig = isonum_721(chr);
572 chr += rr->len;
573 len -= rr->len;
574 if (len < 0)
575 goto out; /* corrupted isofs */
576
577 switch (sig) {
578 case SIG('R', 'R'):
579 if ((rr->u.RR.flags[0] & RR_SL) == 0)
580 goto out;
581 break;
582 case SIG('S', 'P'):
Andrew Morton12121712005-06-21 17:16:44 -0700583 if (check_sp(rr, inode))
584 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 break;
586 case SIG('S', 'L'):
587 rpnt = get_symlink_chunk(rpnt, rr,
588 link + (PAGE_SIZE - 1));
589 if (rpnt == NULL)
590 goto out;
591 break;
592 case SIG('C', 'E'):
593 /* This tells is if there is a continuation record */
Andrew Morton04f7aa92005-06-21 17:16:45 -0700594 cont_extent = isonum_733(rr->u.CE.extent);
595 cont_offset = isonum_733(rr->u.CE.offset);
596 cont_size = isonum_733(rr->u.CE.size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 default:
598 break;
599 }
600 }
601 MAYBE_CONTINUE(repeat, inode);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700602 kfree(buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 if (rpnt == link)
605 goto fail;
606 brelse(bh);
607 *rpnt = '\0';
608 unlock_kernel();
609 SetPageUptodate(page);
610 kunmap(page);
611 unlock_page(page);
612 return 0;
613
614 /* error exit from macro */
Andrew Morton7fa393a2005-06-21 17:16:43 -0700615out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if (buffer)
617 kfree(buffer);
618 goto fail;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700619out_noread:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 printk("unable to read i-node block");
621 goto fail;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700622out_bad_span:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 printk("symlink spans iso9660 blocks\n");
Andrew Morton7fa393a2005-06-21 17:16:43 -0700624fail:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 brelse(bh);
626 unlock_kernel();
Andrew Morton7fa393a2005-06-21 17:16:43 -0700627error:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 SetPageError(page);
629 kunmap(page);
630 unlock_page(page);
631 return -EIO;
632}
633
634struct address_space_operations isofs_symlink_aops = {
Andrew Morton1d372112005-06-21 17:16:42 -0700635 .readpage = rock_ridge_symlink_readpage
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636};