blob: efefbcce4ce958e2865c824dcc2fe34f88b69cab [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 Viro94f2f7152005-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 Mortonba40aaf2005-06-21 17:16:46 -070025struct 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
Andrew Morton12121712005-06-21 17:16:44 -070035/*
36 * This is a way of ensuring that we have something in the system
37 * use fields that is compatible with Rock Ridge. Return zero on success.
38 */
39
40static int check_sp(struct rock_ridge *rr, struct inode *inode)
41{
42 if (rr->u.SP.magic[0] != 0xbe)
43 return -1;
44 if (rr->u.SP.magic[1] != 0xef)
45 return -1;
46 ISOFS_SB(inode->i_sb)->s_rock_offset = rr->u.SP.skip;
47 return 0;
48}
49
Andrew Morton76ab07e2005-06-21 17:16:46 -070050static void setup_rock_ridge(struct iso_directory_record *de,
Andrew Mortonba40aaf2005-06-21 17:16:46 -070051 struct inode *inode, struct rock_state *rs)
Andrew Morton76ab07e2005-06-21 17:16:46 -070052{
Andrew Mortonba40aaf2005-06-21 17:16:46 -070053 rs->len = sizeof(struct iso_directory_record) + de->name_len[0];
54 if (rs->len & 1)
55 (rs->len)++;
56 rs->chr = (unsigned char *)de + rs->len;
57 rs->len = *((unsigned char *)de) - rs->len;
58 if (rs->len < 0)
59 rs->len = 0;
Andrew Morton76ab07e2005-06-21 17:16:46 -070060
61 if (ISOFS_SB(inode->i_sb)->s_rock_offset != -1) {
Andrew Mortonba40aaf2005-06-21 17:16:46 -070062 rs->len -= ISOFS_SB(inode->i_sb)->s_rock_offset;
63 rs->chr += ISOFS_SB(inode->i_sb)->s_rock_offset;
64 if (rs->len < 0)
65 rs->len = 0;
Andrew Morton76ab07e2005-06-21 17:16:46 -070066 }
Andrew Morton1d372112005-06-21 17:16:42 -070067}
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Andrew Mortonba40aaf2005-06-21 17:16:46 -070069static void init_rock_state(struct rock_state *rs, struct inode *inode)
70{
71 memset(rs, 0, sizeof(*rs));
72 rs->inode = inode;
73}
74
75/*
76 * Returns 0 if the caller should continue scanning, 1 if the scan must end
77 * and -ve on error.
78 */
79static int rock_continue(struct rock_state *rs)
80{
81 int ret = 1;
82
83 kfree(rs->buffer);
84 rs->buffer = NULL;
85 if (rs->cont_extent) {
86 struct buffer_head *bh;
87
88 rs->buffer = kmalloc(rs->cont_size, GFP_KERNEL);
89 if (!rs->buffer) {
90 ret = -ENOMEM;
91 goto out;
92 }
93 ret = -EIO;
94 bh = sb_bread(rs->inode->i_sb, rs->cont_extent);
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 }
108out:
109 kfree(rs->buffer);
110 rs->buffer = NULL;
111 return ret;
112}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114/* return length of name field; 0: not found, -1: to be ignored */
Andrew Morton1d372112005-06-21 17:16:42 -0700115int get_rock_ridge_filename(struct iso_directory_record *de,
116 char *retname, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700118 struct rock_state rs;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700119 struct rock_ridge *rr;
120 int sig;
121 int retnamlen = 0;
122 int truncate = 0;
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700123 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Andrew Morton1d372112005-06-21 17:16:42 -0700125 if (!ISOFS_SB(inode->i_sb)->s_rock)
126 return 0;
127 *retname = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700129 init_rock_state(&rs, inode);
130 setup_rock_ridge(de, inode, &rs);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700131repeat:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700133 while (rs.len > 2) { /* There may be one byte for padding somewhere */
134 rr = (struct rock_ridge *)rs.chr;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700135 if (rr->len < 3)
136 goto out; /* Something got screwed up here */
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700137 sig = isonum_721(rs.chr);
138 rs.chr += rr->len;
139 rs.len -= rr->len;
140 if (rs.len < 0)
Andrew Morton7fa393a2005-06-21 17:16:43 -0700141 goto out; /* corrupted isofs */
Andrew Morton1d372112005-06-21 17:16:42 -0700142
Andrew Morton7fa393a2005-06-21 17:16:43 -0700143 switch (sig) {
144 case SIG('R', 'R'):
145 if ((rr->u.RR.flags[0] & RR_NM) == 0)
146 goto out;
147 break;
148 case SIG('S', 'P'):
Andrew Morton12121712005-06-21 17:16:44 -0700149 if (check_sp(rr, inode))
150 goto out;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700151 break;
152 case SIG('C', 'E'):
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700153 rs.cont_extent = isonum_733(rr->u.CE.extent);
154 rs.cont_offset = isonum_733(rr->u.CE.offset);
155 rs.cont_size = isonum_733(rr->u.CE.size);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700156 break;
157 case SIG('N', 'M'):
158 if (truncate)
Andrew Morton1d372112005-06-21 17:16:42 -0700159 break;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700160 if (rr->len < 5)
Andrew Morton1d372112005-06-21 17:16:42 -0700161 break;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700162 /*
163 * If the flags are 2 or 4, this indicates '.' or '..'.
164 * We don't want to do anything with this, because it
165 * screws up the code that calls us. We don't really
166 * care anyways, since we can just use the non-RR
167 * name.
168 */
169 if (rr->u.NM.flags & 6)
Andrew Morton1d372112005-06-21 17:16:42 -0700170 break;
Andrew Morton1d372112005-06-21 17:16:42 -0700171
Andrew Morton7fa393a2005-06-21 17:16:43 -0700172 if (rr->u.NM.flags & ~1) {
173 printk("Unsupported NM flag settings (%d)\n",
174 rr->u.NM.flags);
Andrew Morton1d372112005-06-21 17:16:42 -0700175 break;
176 }
Andrew Morton7fa393a2005-06-21 17:16:43 -0700177 if ((strlen(retname) + rr->len - 5) >= 254) {
178 truncate = 1;
179 break;
180 }
181 strncat(retname, rr->u.NM.name, rr->len - 5);
182 retnamlen += rr->len - 5;
183 break;
184 case SIG('R', 'E'):
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700185 kfree(rs.buffer);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700186 return -1;
187 default:
188 break;
Andrew Morton1d372112005-06-21 17:16:42 -0700189 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 }
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700191 ret = rock_continue(&rs);
192 if (ret == 0)
193 goto repeat;
194 if (ret == 1)
195 return retnamlen; /* If 0, this file did not have a NM field */
Andrew Morton7fa393a2005-06-21 17:16:43 -0700196out:
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700197 kfree(rs.buffer);
198 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
201static int
202parse_rock_ridge_inode_internal(struct iso_directory_record *de,
203 struct inode *inode, int regard_xa)
204{
Andrew Morton1d372112005-06-21 17:16:42 -0700205 int symlink_len = 0;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700206 int cnt, sig;
207 struct inode *reloc;
208 struct rock_ridge *rr;
209 int rootflag;
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700210 struct rock_state rs;
211 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Andrew Morton1d372112005-06-21 17:16:42 -0700213 if (!ISOFS_SB(inode->i_sb)->s_rock)
214 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700216 init_rock_state(&rs, inode);
217 setup_rock_ridge(de, inode, &rs);
Andrew Morton1d372112005-06-21 17:16:42 -0700218 if (regard_xa) {
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700219 rs.chr += 14;
220 rs.len -= 14;
221 if (rs.len < 0)
222 rs.len = 0;
Andrew Morton1d372112005-06-21 17:16:42 -0700223 }
224
Andrew Morton7fa393a2005-06-21 17:16:43 -0700225repeat:
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700226 while (rs.len > 2) { /* There may be one byte for padding somewhere */
227 rr = (struct rock_ridge *)rs.chr;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700228 if (rr->len < 3)
229 goto out; /* Something got screwed up here */
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700230 sig = isonum_721(rs.chr);
231 rs.chr += rr->len;
232 rs.len -= rr->len;
233 if (rs.len < 0)
Andrew Morton7fa393a2005-06-21 17:16:43 -0700234 goto out; /* corrupted isofs */
Andrew Morton1d372112005-06-21 17:16:42 -0700235
Andrew Morton7fa393a2005-06-21 17:16:43 -0700236 switch (sig) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237#ifndef CONFIG_ZISOFS /* No flag for SF or ZF */
Andrew Morton7fa393a2005-06-21 17:16:43 -0700238 case SIG('R', 'R'):
239 if ((rr->u.RR.flags[0] &
240 (RR_PX | RR_TF | RR_SL | RR_CL)) == 0)
Andrew Morton1d372112005-06-21 17:16:42 -0700241 goto out;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700242 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243#endif
Andrew Morton7fa393a2005-06-21 17:16:43 -0700244 case SIG('S', 'P'):
Andrew Morton12121712005-06-21 17:16:44 -0700245 if (check_sp(rr, inode))
246 goto out;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700247 break;
248 case SIG('C', 'E'):
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700249 rs.cont_extent = isonum_733(rr->u.CE.extent);
250 rs.cont_offset = isonum_733(rr->u.CE.offset);
251 rs.cont_size = isonum_733(rr->u.CE.size);
Andrew Morton7fa393a2005-06-21 17:16:43 -0700252 break;
253 case SIG('E', 'R'):
254 ISOFS_SB(inode->i_sb)->s_rock = 1;
255 printk(KERN_DEBUG "ISO 9660 Extensions: ");
256 {
257 int p;
258 for (p = 0; p < rr->u.ER.len_id; p++)
259 printk("%c", rr->u.ER.data[p]);
Andrew Morton1d372112005-06-21 17:16:42 -0700260 }
Andrew Morton7fa393a2005-06-21 17:16:43 -0700261 printk("\n");
262 break;
263 case SIG('P', 'X'):
264 inode->i_mode = isonum_733(rr->u.PX.mode);
265 inode->i_nlink = isonum_733(rr->u.PX.n_links);
266 inode->i_uid = isonum_733(rr->u.PX.uid);
267 inode->i_gid = isonum_733(rr->u.PX.gid);
268 break;
269 case SIG('P', 'N'):
270 {
271 int high, low;
272 high = isonum_733(rr->u.PN.dev_high);
273 low = isonum_733(rr->u.PN.dev_low);
274 /*
275 * The Rock Ridge standard specifies that if
276 * sizeof(dev_t) <= 4, then the high field is
277 * unused, and the device number is completely
278 * stored in the low field. Some writers may
279 * ignore this subtlety,
280 * and as a result we test to see if the entire
281 * device number is
282 * stored in the low field, and use that.
283 */
284 if ((low & ~0xff) && high == 0) {
285 inode->i_rdev =
286 MKDEV(low >> 8, low & 0xff);
287 } else {
288 inode->i_rdev =
289 MKDEV(high, low);
290 }
291 }
292 break;
293 case SIG('T', 'F'):
294 /*
295 * Some RRIP writers incorrectly place ctime in the
296 * TF_CREATE field. Try to handle this correctly for
297 * either case.
298 */
299 /* Rock ridge never appears on a High Sierra disk */
300 cnt = 0;
301 if (rr->u.TF.flags & TF_CREATE) {
302 inode->i_ctime.tv_sec =
303 iso_date(rr->u.TF.times[cnt++].time,
304 0);
305 inode->i_ctime.tv_nsec = 0;
306 }
307 if (rr->u.TF.flags & TF_MODIFY) {
308 inode->i_mtime.tv_sec =
309 iso_date(rr->u.TF.times[cnt++].time,
310 0);
311 inode->i_mtime.tv_nsec = 0;
312 }
313 if (rr->u.TF.flags & TF_ACCESS) {
314 inode->i_atime.tv_sec =
315 iso_date(rr->u.TF.times[cnt++].time,
316 0);
317 inode->i_atime.tv_nsec = 0;
318 }
319 if (rr->u.TF.flags & TF_ATTRIBUTES) {
320 inode->i_ctime.tv_sec =
321 iso_date(rr->u.TF.times[cnt++].time,
322 0);
323 inode->i_ctime.tv_nsec = 0;
324 }
325 break;
326 case SIG('S', 'L'):
327 {
328 int slen;
329 struct SL_component *slp;
330 struct SL_component *oldslp;
331 slen = rr->len - 5;
332 slp = &rr->u.SL.link;
333 inode->i_size = symlink_len;
334 while (slen > 1) {
335 rootflag = 0;
336 switch (slp->flags & ~1) {
337 case 0:
338 inode->i_size +=
339 slp->len;
340 break;
341 case 2:
342 inode->i_size += 1;
343 break;
344 case 4:
345 inode->i_size += 2;
346 break;
347 case 8:
348 rootflag = 1;
349 inode->i_size += 1;
350 break;
351 default:
352 printk("Symlink component flag "
353 "not implemented\n");
354 }
355 slen -= slp->len + 2;
356 oldslp = slp;
357 slp = (struct SL_component *)
358 (((char *)slp) + slp->len + 2);
359
360 if (slen < 2) {
361 if (((rr->u.SL.
362 flags & 1) != 0)
363 &&
364 ((oldslp->
365 flags & 1) == 0))
366 inode->i_size +=
367 1;
368 break;
369 }
370
371 /*
372 * If this component record isn't
373 * continued, then append a '/'.
374 */
375 if (!rootflag
376 && (oldslp->flags & 1) == 0)
377 inode->i_size += 1;
378 }
379 }
380 symlink_len = inode->i_size;
381 break;
382 case SIG('R', 'E'):
383 printk(KERN_WARNING "Attempt to read inode for "
384 "relocated directory\n");
385 goto out;
386 case SIG('C', 'L'):
387 ISOFS_I(inode)->i_first_extent =
388 isonum_733(rr->u.CL.location);
389 reloc =
390 isofs_iget(inode->i_sb,
391 ISOFS_I(inode)->i_first_extent,
392 0);
393 if (!reloc)
394 goto out;
395 inode->i_mode = reloc->i_mode;
396 inode->i_nlink = reloc->i_nlink;
397 inode->i_uid = reloc->i_uid;
398 inode->i_gid = reloc->i_gid;
399 inode->i_rdev = reloc->i_rdev;
400 inode->i_size = reloc->i_size;
401 inode->i_blocks = reloc->i_blocks;
402 inode->i_atime = reloc->i_atime;
403 inode->i_ctime = reloc->i_ctime;
404 inode->i_mtime = reloc->i_mtime;
405 iput(reloc);
406 break;
407#ifdef CONFIG_ZISOFS
408 case SIG('Z', 'F'): {
409 int algo;
410
411 if (ISOFS_SB(inode->i_sb)->s_nocompress)
412 break;
413 algo = isonum_721(rr->u.ZF.algorithm);
414 if (algo == SIG('p', 'z')) {
415 int block_shift =
416 isonum_711(&rr->u.ZF.parms[1]);
417 if (block_shift < PAGE_CACHE_SHIFT
418 || block_shift > 17) {
419 printk(KERN_WARNING "isofs: "
420 "Can't handle ZF block "
421 "size of 2^%d\n",
422 block_shift);
423 } else {
424 /*
425 * Note: we don't change
426 * i_blocks here
427 */
428 ISOFS_I(inode)->i_file_format =
429 isofs_file_compressed;
430 /*
431 * Parameters to compression
432 * algorithm (header size,
433 * block size)
434 */
435 ISOFS_I(inode)->i_format_parm[0] =
436 isonum_711(&rr->u.ZF.parms[0]);
437 ISOFS_I(inode)->i_format_parm[1] =
438 isonum_711(&rr->u.ZF.parms[1]);
439 inode->i_size =
440 isonum_733(rr->u.ZF.
441 real_size);
442 }
443 } else {
444 printk(KERN_WARNING
445 "isofs: Unknown ZF compression "
446 "algorithm: %c%c\n",
447 rr->u.ZF.algorithm[0],
448 rr->u.ZF.algorithm[1]);
449 }
450 break;
451 }
452#endif
453 default:
454 break;
Andrew Morton1d372112005-06-21 17:16:42 -0700455 }
456 }
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700457 ret = rock_continue(&rs);
458 if (ret == 0)
459 goto repeat;
460 if (ret == 1)
461 ret = 0;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700462out:
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700463 kfree(rs.buffer);
464 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465}
466
467static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
468{
469 int slen;
470 int rootflag;
471 struct SL_component *oldslp;
472 struct SL_component *slp;
473 slen = rr->len - 5;
474 slp = &rr->u.SL.link;
475 while (slen > 1) {
476 rootflag = 0;
477 switch (slp->flags & ~1) {
478 case 0:
479 if (slp->len > plimit - rpnt)
480 return NULL;
481 memcpy(rpnt, slp->text, slp->len);
Andrew Morton1d372112005-06-21 17:16:42 -0700482 rpnt += slp->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 break;
484 case 2:
485 if (rpnt >= plimit)
486 return NULL;
Andrew Morton1d372112005-06-21 17:16:42 -0700487 *rpnt++ = '.';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 break;
489 case 4:
490 if (2 > plimit - rpnt)
491 return NULL;
Andrew Morton1d372112005-06-21 17:16:42 -0700492 *rpnt++ = '.';
493 *rpnt++ = '.';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 break;
495 case 8:
496 if (rpnt >= plimit)
497 return NULL;
498 rootflag = 1;
Andrew Morton1d372112005-06-21 17:16:42 -0700499 *rpnt++ = '/';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 break;
501 default:
502 printk("Symlink component flag not implemented (%d)\n",
Andrew Morton1d372112005-06-21 17:16:42 -0700503 slp->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 }
505 slen -= slp->len + 2;
506 oldslp = slp;
Andrew Morton1d372112005-06-21 17:16:42 -0700507 slp = (struct SL_component *)((char *)slp + slp->len + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
509 if (slen < 2) {
510 /*
511 * If there is another SL record, and this component
512 * record isn't continued, then add a slash.
513 */
514 if ((!rootflag) && (rr->u.SL.flags & 1) &&
515 !(oldslp->flags & 1)) {
516 if (rpnt >= plimit)
517 return NULL;
Andrew Morton1d372112005-06-21 17:16:42 -0700518 *rpnt++ = '/';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 }
520 break;
521 }
522
523 /*
524 * If this component record isn't continued, then append a '/'.
525 */
526 if (!rootflag && !(oldslp->flags & 1)) {
527 if (rpnt >= plimit)
528 return NULL;
Andrew Morton1d372112005-06-21 17:16:42 -0700529 *rpnt++ = '/';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 }
531 }
532 return rpnt;
533}
534
Andrew Morton1d372112005-06-21 17:16:42 -0700535int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
Andrew Morton1d372112005-06-21 17:16:42 -0700537 int result = parse_rock_ridge_inode_internal(de, inode, 0);
538 /* if rockridge flag was reset and we didn't look for attributes
539 * behind eventual XA attributes, have a look there */
540 if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1)
541 && (ISOFS_SB(inode->i_sb)->s_rock == 2)) {
542 result = parse_rock_ridge_inode_internal(de, inode, 14);
543 }
544 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545}
546
547/* readpage() for symlinks: reads symlink contents into the page and either
548 makes it uptodate and returns 0 or returns error (-EIO) */
549
550static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
551{
552 struct inode *inode = page->mapping->host;
Andrew Morton1d372112005-06-21 17:16:42 -0700553 struct iso_inode_info *ei = ISOFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 char *link = kmap(page);
555 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
556 struct buffer_head *bh;
557 char *rpnt = link;
558 unsigned char *pnt;
Andrew Morton76ab07e2005-06-21 17:16:46 -0700559 struct iso_directory_record *raw_de;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 unsigned long block, offset;
561 int sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 struct rock_ridge *rr;
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700563 struct rock_state rs;
564 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566 if (!ISOFS_SB(inode->i_sb)->s_rock)
567 goto error;
568
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700569 init_rock_state(&rs, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 block = ei->i_iget5_block;
571 lock_kernel();
572 bh = sb_bread(inode->i_sb, block);
573 if (!bh)
574 goto out_noread;
575
Andrew Morton1d372112005-06-21 17:16:42 -0700576 offset = ei->i_iget5_offset;
577 pnt = (unsigned char *)bh->b_data + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Andrew Morton76ab07e2005-06-21 17:16:46 -0700579 raw_de = (struct iso_directory_record *)pnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 /*
582 * If we go past the end of the buffer, there is some sort of error.
583 */
584 if (offset + *pnt > bufsize)
585 goto out_bad_span;
586
587 /* Now test for possible Rock Ridge extensions which will override
588 some of these numbers in the inode structure. */
589
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700590 setup_rock_ridge(raw_de, inode, &rs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Andrew Morton7fa393a2005-06-21 17:16:43 -0700592repeat:
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700593 while (rs.len > 2) { /* There may be one byte for padding somewhere */
594 rr = (struct rock_ridge *)rs.chr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 if (rr->len < 3)
596 goto out; /* Something got screwed up here */
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700597 sig = isonum_721(rs.chr);
598 rs.chr += rr->len;
599 rs.len -= rr->len;
600 if (rs.len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 goto out; /* corrupted isofs */
602
603 switch (sig) {
604 case SIG('R', 'R'):
605 if ((rr->u.RR.flags[0] & RR_SL) == 0)
606 goto out;
607 break;
608 case SIG('S', 'P'):
Andrew Morton12121712005-06-21 17:16:44 -0700609 if (check_sp(rr, inode))
610 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 break;
612 case SIG('S', 'L'):
613 rpnt = get_symlink_chunk(rpnt, rr,
614 link + (PAGE_SIZE - 1));
615 if (rpnt == NULL)
616 goto out;
617 break;
618 case SIG('C', 'E'):
619 /* This tells is if there is a continuation record */
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700620 rs.cont_extent = isonum_733(rr->u.CE.extent);
621 rs.cont_offset = isonum_733(rr->u.CE.offset);
622 rs.cont_size = isonum_733(rr->u.CE.size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 default:
624 break;
625 }
626 }
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700627 ret = rock_continue(&rs);
628 if (ret == 0)
629 goto repeat;
630 if (ret < 0)
631 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 if (rpnt == link)
634 goto fail;
635 brelse(bh);
636 *rpnt = '\0';
637 unlock_kernel();
638 SetPageUptodate(page);
639 kunmap(page);
640 unlock_page(page);
641 return 0;
642
643 /* error exit from macro */
Andrew Morton7fa393a2005-06-21 17:16:43 -0700644out:
Andrew Mortonba40aaf2005-06-21 17:16:46 -0700645 kfree(rs.buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 goto fail;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700647out_noread:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 printk("unable to read i-node block");
649 goto fail;
Andrew Morton7fa393a2005-06-21 17:16:43 -0700650out_bad_span:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 printk("symlink spans iso9660 blocks\n");
Andrew Morton7fa393a2005-06-21 17:16:43 -0700652fail:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 brelse(bh);
654 unlock_kernel();
Andrew Morton7fa393a2005-06-21 17:16:43 -0700655error:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 SetPageError(page);
657 kunmap(page);
658 unlock_page(page);
659 return -EIO;
660}
661
662struct address_space_operations isofs_symlink_aops = {
Andrew Morton1d372112005-06-21 17:16:42 -0700663 .readpage = rock_ridge_symlink_readpage
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664};