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