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