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