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