This source file includes following definitions.
- isofs_put_super
- parse_options
- isofs_read_super
- isofs_statfs
- isofs_bmap
- isofs_read_inode
- isofs_lookup_grandparent
- leak_check_malloc
- leak_check_free_s
- leak_check_bread
- leak_check_brelse
1
2
3
4
5
6
7
8 #include <linux/config.h>
9 #include <linux/stat.h>
10 #include <linux/sched.h>
11 #include <linux/iso_fs.h>
12 #include <linux/kernel.h>
13 #include <linux/mm.h>
14 #include <linux/string.h>
15 #include <linux/locks.h>
16
17 #include <asm/system.h>
18 #include <asm/segment.h>
19 #include <linux/errno.h>
20
21 #if defined(CONFIG_BLK_DEV_SR)
22 extern int check_cdrom_media_change(int, int);
23 #endif
24 #if defined(CONFIG_CDU31A)
25 extern int check_cdu31a_media_change(int, int);
26 #endif
27 #if defined(CONFIG_MCD)
28 extern int check_mcd_media_change(int, int);
29 #endif
30
31 #ifdef LEAK_CHECK
32 static int check_malloc = 0;
33 static int check_bread = 0;
34 #endif
35
36 void isofs_put_super(struct super_block *sb)
37 {
38 lock_super(sb);
39
40 #ifdef LEAK_CHECK
41 printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
42 check_malloc, check_bread);
43 #endif
44 sb->s_dev = 0;
45 unlock_super(sb);
46 return;
47 }
48
49 static struct super_operations isofs_sops = {
50 isofs_read_inode,
51 NULL,
52 NULL,
53 NULL,
54 isofs_put_super,
55 NULL,
56 isofs_statfs,
57 NULL
58 };
59
60
61
62 static int parse_options(char *options,char *map,char *conversion, char * rock, char * cruft, unsigned int * blocksize)
63 {
64 char *this_char,*value;
65
66 *map = 'n';
67 *rock = 'y';
68 *cruft = 'n';
69 *conversion = 'a';
70 *blocksize = 1024;
71 if (!options) return 1;
72 for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
73 if (strncmp(this_char,"norock",6) == 0) {
74 *rock = 'n';
75 continue;
76 };
77 if (strncmp(this_char,"cruft",5) == 0) {
78 *cruft = 'y';
79 continue;
80 };
81 if ((value = strchr(this_char,'=')) != NULL)
82 *value++ = 0;
83 if (!strcmp(this_char,"map") && value) {
84 if (value[0] && !value[1] && strchr("on",*value))
85 *map = *value;
86 else if (!strcmp(value,"off")) *map = 'o';
87 else if (!strcmp(value,"normal")) *map = 'n';
88 else return 0;
89 }
90 else if (!strcmp(this_char,"conv") && value) {
91 if (value[0] && !value[1] && strchr("bta",*value))
92 *conversion = *value;
93 else if (!strcmp(value,"binary")) *conversion = 'b';
94 else if (!strcmp(value,"text")) *conversion = 't';
95 else if (!strcmp(value,"mtext")) *conversion = 'm';
96 else if (!strcmp(value,"auto")) *conversion = 'a';
97 else return 0;
98 }
99 else if (!strcmp(this_char,"block") && value) {
100 char * vpnt = value;
101 unsigned int ivalue;
102 ivalue = 0;
103 while(*vpnt){
104 if(*vpnt < '0' || *vpnt > '9') break;
105 ivalue = ivalue * 10 + (*vpnt - '0');
106 vpnt++;
107 };
108 if (*vpnt) return 0;
109 if (ivalue != 1024 && ivalue != 2048) return 0;
110 *blocksize = ivalue;
111 }
112 else return 0;
113 }
114 return 1;
115 }
116
117 struct super_block *isofs_read_super(struct super_block *s,void *data,
118 int silent)
119 {
120 struct buffer_head *bh;
121 int iso_blknum;
122 unsigned int blocksize, blocksize_bits;
123 int high_sierra;
124 int dev=s->s_dev;
125 struct iso_volume_descriptor *vdp;
126 struct hs_volume_descriptor *hdp;
127
128 struct iso_primary_descriptor *pri = NULL;
129 struct hs_primary_descriptor *h_pri = NULL;
130
131 struct iso_directory_record *rootp;
132
133 char map, conversion, rock, cruft;
134
135 if (!parse_options((char *) data,&map,&conversion, &rock, &cruft, &blocksize)) {
136 s->s_dev = 0;
137 return NULL;
138 }
139
140 blocksize_bits = 0;
141 {
142 int i = blocksize;
143 while (i != 1){
144 blocksize_bits++;
145 i >>=1;
146 };
147 };
148 set_blocksize(dev, blocksize);
149
150 lock_super(s);
151
152 s->u.isofs_sb.s_high_sierra = high_sierra = 0;
153
154 for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
155 if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), blocksize))) {
156 s->s_dev=0;
157 printk("isofs_read_super: bread failed, dev 0x%x iso_blknum %d\n",
158 dev, iso_blknum);
159 unlock_super(s);
160 return NULL;
161 }
162
163 vdp = (struct iso_volume_descriptor *)bh->b_data;
164 hdp = (struct hs_volume_descriptor *)bh->b_data;
165
166
167 if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
168 if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
169 goto out;
170 if (isonum_711 (hdp->type) == ISO_VD_END)
171 goto out;
172
173 s->u.isofs_sb.s_high_sierra = 1;
174 high_sierra = 1;
175 rock = 'n';
176 h_pri = (struct hs_primary_descriptor *)vdp;
177 break;
178 };
179
180 if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
181 if (isonum_711 (vdp->type) != ISO_VD_PRIMARY)
182 goto out;
183 if (isonum_711 (vdp->type) == ISO_VD_END)
184 goto out;
185
186 pri = (struct iso_primary_descriptor *)vdp;
187 break;
188 };
189
190 brelse(bh);
191 }
192 if(iso_blknum == 100) {
193 if (!silent)
194 printk("Unable to identify CD-ROM format.\n");
195 s->s_dev = 0;
196 unlock_super(s);
197 return NULL;
198 };
199
200
201 if(high_sierra){
202 rootp = (struct iso_directory_record *) h_pri->root_directory_record;
203 if (isonum_723 (h_pri->volume_set_size) != 1) {
204 printk("Multi-volume disks not (yet) supported.\n");
205 goto out;
206 };
207 s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size);
208 s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size);
209 s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size);
210 } else {
211 rootp = (struct iso_directory_record *) pri->root_directory_record;
212 if (isonum_723 (pri->volume_set_size) != 1) {
213 printk("Multi-volume disks not (yet) supported.\n");
214 goto out;
215 };
216 s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size);
217 s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size);
218 s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size);
219 }
220
221 s->u.isofs_sb.s_ninodes = 0;
222
223 s->u.isofs_sb.s_firstdatazone = isonum_733( rootp->extent) <<
224 (ISOFS_BLOCK_BITS - blocksize_bits);
225 s->s_magic = ISOFS_SUPER_MAGIC;
226
227
228
229
230
231
232 s->s_flags = MS_RDONLY ;
233
234 if(s->u.isofs_sb.s_log_zone_size != (1 << ISOFS_BLOCK_BITS)) {
235 printk("1 <<Block bits != Block size\n");
236 goto out;
237 };
238
239 brelse(bh);
240
241 printk("Max size:%d Log zone size:%d\n",s->u.isofs_sb.s_max_size,
242 s->u.isofs_sb.s_log_zone_size);
243 printk("First datazone:%d Root inode number %d\n",s->u.isofs_sb.s_firstdatazone,
244 isonum_733 (rootp->extent) << ISOFS_BLOCK_BITS);
245 if(high_sierra) printk("Disc in High Sierra format.\n");
246 unlock_super(s);
247
248
249 s->s_dev = dev;
250 s->s_op = &isofs_sops;
251 s->u.isofs_sb.s_mapping = map;
252 s->u.isofs_sb.s_rock = (rock == 'y' ? 1 : 0);
253 s->u.isofs_sb.s_conversion = conversion;
254 s->u.isofs_sb.s_cruft = cruft;
255 s->s_blocksize = blocksize;
256 s->s_blocksize_bits = blocksize_bits;
257 s->s_mounted = iget(s, isonum_733 (rootp->extent) << ISOFS_BLOCK_BITS);
258 unlock_super(s);
259
260 if (!(s->s_mounted)) {
261 s->s_dev=0;
262 printk("get root inode failed\n");
263 return NULL;
264 }
265 #if defined(CONFIG_BLK_DEV_SR)
266 if(MAJOR(s->s_dev) == 11) {
267
268 if(check_cdrom_media_change(s->s_dev, 0))
269 goto out;
270 };
271 #endif
272 #if defined(CONFIG_CDU31A)
273 if(MAJOR(s->s_dev) == 15) {
274
275 if(check_cdu31a_media_change(s->s_dev, 0))
276 goto out;
277 };
278 #endif
279 #if defined(CONFIG_MCD)
280 if(MAJOR(s->s_dev) == 23) {
281
282 if(check_mcd_media_change(s->s_dev, 0))
283 goto out;
284 };
285 #endif
286 return s;
287 out:
288 brelse(bh);
289 s->s_dev = 0;
290 unlock_super(s);
291 return NULL;
292 }
293
294 void isofs_statfs (struct super_block *sb, struct statfs *buf)
295 {
296 put_fs_long(ISOFS_SUPER_MAGIC, &buf->f_type);
297 put_fs_long(1 << ISOFS_BLOCK_BITS, &buf->f_bsize);
298 put_fs_long(sb->u.isofs_sb.s_nzones, &buf->f_blocks);
299 put_fs_long(0, &buf->f_bfree);
300 put_fs_long(0, &buf->f_bavail);
301 put_fs_long(sb->u.isofs_sb.s_ninodes, &buf->f_files);
302 put_fs_long(0, &buf->f_ffree);
303 put_fs_long(NAME_MAX, &buf->f_namelen);
304
305 }
306
307 int isofs_bmap(struct inode * inode,int block)
308 {
309
310 if (block<0) {
311 printk("_isofs_bmap: block<0");
312 return 0;
313 }
314 return inode->u.isofs_i.i_first_extent + block;
315 }
316
317 void isofs_read_inode(struct inode * inode)
318 {
319 struct buffer_head * bh;
320 unsigned char *pnt = NULL;
321 void *cpnt = NULL;
322 struct iso_directory_record * raw_inode;
323 int high_sierra;
324 int block;
325 int i;
326
327 block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
328 if (!(bh=bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode))))
329 panic("unable to read i-node block");
330
331 pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
332
333 raw_inode = ((struct iso_directory_record *) pnt);
334 high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
335
336
337 if ((inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1)) + *pnt > ISOFS_BUFFER_SIZE(inode)){
338 cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
339 memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(inode));
340 brelse(bh);
341 if (!(bh = bread(inode->i_dev,++block, ISOFS_BUFFER_SIZE(inode))))
342 panic("unable to read i-node block");
343 memcpy(cpnt+ISOFS_BUFFER_SIZE(inode), bh->b_data, ISOFS_BUFFER_SIZE(inode));
344 pnt = ((unsigned char *) cpnt) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
345 raw_inode = ((struct iso_directory_record *) pnt);
346 };
347
348 inode->i_mode = S_IRUGO;
349 inode->i_nlink = 1;
350
351 if (raw_inode->flags[-high_sierra] & 2) {
352 inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
353 inode->i_nlink = 2;
354
355 } else {
356 inode->i_mode = S_IRUGO;
357 inode->i_nlink = 1;
358 inode->i_mode |= S_IFREG;
359
360 for(i=0; i< raw_inode->name_len[0]; i++)
361 if(raw_inode->name[i]=='.' || raw_inode->name[i]==';')
362 break;
363 if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';')
364 inode->i_mode |= S_IXUGO;
365 };
366 inode->i_uid = 0;
367 inode->i_gid = 0;
368 inode->i_size = isonum_733 (raw_inode->size);
369
370
371
372 if((inode->i_size < 0 || inode->i_size > 700000000) &&
373 inode->i_sb->u.isofs_sb.s_cruft == 'n') {
374 printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n");
375 inode->i_sb->u.isofs_sb.s_cruft = 'y';
376 };
377
378
379
380
381
382 if(inode->i_sb->u.isofs_sb.s_cruft == 'y' &&
383 inode->i_size & 0xff000000){
384
385 inode->i_size &= 0x00ffffff;
386 };
387
388 if (isonum_723 (raw_inode->volume_sequence_number) != 1) {
389 panic("Multi volume CD somehow got mounted.\n");
390 };
391
392 if (raw_inode->interleave[0]) {
393 printk("Interleaved files not (yet) supported.\n");
394 inode->i_size = 0;
395 };
396
397 #ifdef DEBUG
398
399
400 if(raw_inode->ext_attr_length[0] != 0){
401 printk("Extended attributes present for ISO file (%d).\n",
402 inode->i_ino);
403 }
404 #endif
405
406
407
408 if(raw_inode->file_unit_size[0] != 0){
409 printk("File unit size != 0 for ISO file.(%d)\n",inode->i_ino);
410 }
411
412
413
414 if((raw_inode->flags[-high_sierra] & ~2)!= 0){
415 printk("Unusual flag settings for ISO file.(%d %x)\n",
416 inode->i_ino, raw_inode->flags[-high_sierra]);
417 }
418
419 #ifdef DEBUG
420 printk("Get inode %d: %d %d: %d\n",inode->i_ino, block,
421 ((int)pnt) & 0x3ff, inode->i_size);
422 #endif
423
424 inode->i_mtime = inode->i_atime = inode->i_ctime =
425 iso_date(raw_inode->date, high_sierra);
426
427 inode->u.isofs_i.i_first_extent = isonum_733 (raw_inode->extent) <<
428 (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(inode));
429
430 inode->u.isofs_i.i_backlink = 0xffffffff;
431 switch (inode->i_sb->u.isofs_sb.s_conversion){
432 case 'a':
433 inode->u.isofs_i.i_file_format = ISOFS_FILE_UNKNOWN;
434 break;
435 case 'b':
436 inode->u.isofs_i.i_file_format = ISOFS_FILE_BINARY;
437 break;
438 case 't':
439 inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT;
440 break;
441 case 'm':
442 inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT_M;
443 break;
444 };
445
446
447
448
449
450 if (!high_sierra)
451 parse_rock_ridge_inode(raw_inode, inode);
452
453 #ifdef DEBUG
454 printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent);
455 #endif
456 brelse(bh);
457
458 if (cpnt) {
459 kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS);
460 cpnt = NULL;
461 };
462
463 inode->i_op = NULL;
464 if (S_ISREG(inode->i_mode))
465 inode->i_op = &isofs_file_inode_operations;
466 else if (S_ISDIR(inode->i_mode))
467 inode->i_op = &isofs_dir_inode_operations;
468 else if (S_ISLNK(inode->i_mode))
469 inode->i_op = &isofs_symlink_inode_operations;
470 else if (S_ISCHR(inode->i_mode))
471 inode->i_op = &chrdev_inode_operations;
472 else if (S_ISBLK(inode->i_mode))
473 inode->i_op = &blkdev_inode_operations;
474 else if (S_ISFIFO(inode->i_mode))
475 init_fifo(inode);
476 }
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497 int isofs_lookup_grandparent(struct inode * parent, int extent) {
498 unsigned int block,offset;
499 int parent_dir, inode_number;
500 int old_offset;
501 void * cpnt = NULL;
502 int result;
503 struct buffer_head * bh;
504 struct iso_directory_record * de;
505
506 offset = 0;
507 block = extent << (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(parent));
508 if (!(bh = bread(parent->i_dev, block, ISOFS_BUFFER_SIZE(parent)))) return 0;
509
510 while (1 == 1) {
511 de = (struct iso_directory_record *) (offset + bh->b_data);
512
513 if (*((char*) de) == 0)
514 {
515 brelse(bh);
516 return -1;
517 }
518
519 offset += *((unsigned char*) de);
520
521 if (offset >= ISOFS_BUFFER_SIZE(parent))
522 {
523 printk(".. Directory not in first block of directory.\n");
524 brelse(bh);
525 return -1;
526 }
527
528 if (de->name_len[0] == 1 && de->name[0] == 1)
529 {
530 parent_dir = find_rock_ridge_relocation(de, parent);
531 brelse(bh);
532 break;
533 };
534 }
535 #ifdef DEBUG
536 printk("Parent dir:%x\n",parent_dir);
537 #endif
538
539
540
541
542 result = -1;
543
544 offset = 0;
545 block = parent_dir << (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(parent));
546 if (!block || !(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
547 return 0;
548
549 while (1==1) {
550 de = (struct iso_directory_record *) (offset + bh->b_data);
551 inode_number = (block << ISOFS_BUFFER_BITS(parent))+(offset & (ISOFS_BUFFER_SIZE(parent) - 1));
552
553
554
555
556 if (*((char*) de) == 0)
557 {
558 brelse(bh);
559 offset = 0;
560 block++;
561 if(block & 1) return -1;
562 if (!block || !(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
563 return -1;
564 continue;
565 }
566
567
568
569
570
571 old_offset = offset;
572 offset += *((unsigned char*) de);
573
574 if (offset >= ISOFS_BUFFER_SIZE(parent))
575 {
576 cpnt = kmalloc(1<<ISOFS_BLOCK_BITS,GFP_KERNEL);
577 memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(parent));
578 de = (struct iso_directory_record *) (old_offset + cpnt);
579 brelse(bh);
580 offset -= ISOFS_BUFFER_SIZE(parent);
581 block++;
582 if((block & 1) == 0) return -1;
583 if (!(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
584 return -1;
585 memcpy(cpnt+ISOFS_BUFFER_SIZE(parent), bh->b_data, ISOFS_BUFFER_SIZE(parent));
586 }
587
588 if (find_rock_ridge_relocation(de, parent) == extent){
589 result = inode_number;
590 goto out;
591 };
592
593 if (cpnt) {
594 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
595 cpnt = NULL;
596 };
597 }
598
599
600
601 out:
602 if (cpnt) {
603 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
604 cpnt = NULL;
605 };
606 brelse(bh);
607 #ifdef DEBUG
608 printk("Resultant Inode %d\n",result);
609 #endif
610 return result;
611 }
612
613 #ifdef LEAK_CHECK
614 #undef malloc
615 #undef free_s
616 #undef bread
617 #undef brelse
618
619 void * leak_check_malloc(unsigned int size){
620 void * tmp;
621 check_malloc++;
622 tmp = kmalloc(size, GFP_KERNEL);
623 return tmp;
624 }
625
626 void leak_check_free_s(void * obj, int size){
627 check_malloc--;
628 return kfree_s(obj, size);
629 }
630
631 struct buffer_head * leak_check_bread(int dev, int block, int size){
632 check_bread++;
633 return bread(dev, block, size);
634 }
635
636 void leak_check_brelse(struct buffer_head * bh){
637 check_bread--;
638 return brelse(bh);
639 }
640
641 #endif