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 panic("unable to read i-node block");
336
337 pnt = ((unsigned char *) bh->b_data
338 + (inode->i_ino & (bufsize - 1)));
339 raw_inode = ((struct iso_directory_record *) pnt);
340 high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
341
342 if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
343 cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
344 memcpy(cpnt, bh->b_data, bufsize);
345 brelse(bh);
346 if (!(bh = bread(inode->i_dev,++block, bufsize)))
347 panic("unable to read i-node block");
348 memcpy((char *)cpnt + bufsize, bh->b_data, bufsize);
349 pnt = ((unsigned char *) cpnt
350 + (inode->i_ino & (bufsize - 1)));
351 raw_inode = ((struct iso_directory_record *) pnt);
352 };
353
354 inode->i_mode = S_IRUGO;
355 inode->i_nlink = 1;
356
357 if (raw_inode->flags[-high_sierra] & 2) {
358 inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
359 inode->i_nlink = 2;
360
361 } else {
362 inode->i_mode = S_IRUGO;
363 inode->i_nlink = 1;
364 inode->i_mode |= S_IFREG;
365
366 for(i=0; i< raw_inode->name_len[0]; i++)
367 if(raw_inode->name[i]=='.' || raw_inode->name[i]==';')
368 break;
369 if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';')
370 inode->i_mode |= S_IXUGO;
371 };
372 inode->i_uid = 0;
373 inode->i_gid = 0;
374 inode->i_size = isonum_733 (raw_inode->size);
375
376
377
378 if((inode->i_size < 0 || inode->i_size > 700000000) &&
379 inode->i_sb->u.isofs_sb.s_cruft == 'n') {
380 printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n");
381 inode->i_sb->u.isofs_sb.s_cruft = 'y';
382 };
383
384
385
386
387
388 if(inode->i_sb->u.isofs_sb.s_cruft == 'y' &&
389 inode->i_size & 0xff000000){
390
391 inode->i_size &= 0x00ffffff;
392 };
393
394 if (isonum_723 (raw_inode->volume_sequence_number) != 1) {
395 printk("Multi volume CD somehow got mounted.\n");
396 };
397
398 if (raw_inode->interleave[0]) {
399 printk("Interleaved files not (yet) supported.\n");
400 inode->i_size = 0;
401 };
402
403 #ifdef DEBUG
404
405
406 if(raw_inode->ext_attr_length[0] != 0){
407 printk("Extended attributes present for ISO file (%ld).\n",
408 inode->i_ino);
409 }
410 #endif
411
412
413
414 if(raw_inode->file_unit_size[0] != 0){
415 printk("File unit size != 0 for ISO file (%ld).\n",inode->i_ino);
416 }
417
418
419
420 if((raw_inode->flags[-high_sierra] & ~2)!= 0){
421 printk("Unusual flag settings for ISO file (%ld %x).\n",
422 inode->i_ino, raw_inode->flags[-high_sierra]);
423 }
424
425 #ifdef DEBUG
426 printk("Get inode %d: %d %d: %d\n",inode->i_ino, block,
427 ((int)pnt) & 0x3ff, inode->i_size);
428 #endif
429
430 inode->i_mtime = inode->i_atime = inode->i_ctime =
431 iso_date(raw_inode->date, high_sierra);
432
433 inode->u.isofs_i.i_first_extent = isonum_733 (raw_inode->extent) <<
434 (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(inode));
435
436 inode->u.isofs_i.i_backlink = 0xffffffff;
437 switch (inode->i_sb->u.isofs_sb.s_conversion){
438 case 'a':
439 inode->u.isofs_i.i_file_format = ISOFS_FILE_UNKNOWN;
440 break;
441 case 'b':
442 inode->u.isofs_i.i_file_format = ISOFS_FILE_BINARY;
443 break;
444 case 't':
445 inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT;
446 break;
447 case 'm':
448 inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT_M;
449 break;
450 };
451
452
453
454
455
456 if (!high_sierra)
457 parse_rock_ridge_inode(raw_inode, inode);
458
459 #ifdef DEBUG
460 printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent);
461 #endif
462 brelse(bh);
463
464 if (cpnt) {
465 kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS);
466 cpnt = NULL;
467 };
468
469 inode->i_op = NULL;
470 if (S_ISREG(inode->i_mode))
471 inode->i_op = &isofs_file_inode_operations;
472 else if (S_ISDIR(inode->i_mode))
473 inode->i_op = &isofs_dir_inode_operations;
474 else if (S_ISLNK(inode->i_mode))
475 inode->i_op = &isofs_symlink_inode_operations;
476 else if (S_ISCHR(inode->i_mode))
477 inode->i_op = &chrdev_inode_operations;
478 else if (S_ISBLK(inode->i_mode))
479 inode->i_op = &blkdev_inode_operations;
480 else if (S_ISFIFO(inode->i_mode))
481 init_fifo(inode);
482 }
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503 int isofs_lookup_grandparent(struct inode * parent, int extent)
504 {
505 unsigned long bufsize = ISOFS_BUFFER_SIZE(parent);
506 unsigned char bufbits = ISOFS_BUFFER_BITS(parent);
507 unsigned int block,offset;
508 int parent_dir, inode_number;
509 int old_offset;
510 void * cpnt = NULL;
511 int result;
512 struct buffer_head * bh;
513 struct iso_directory_record * de;
514
515 offset = 0;
516 block = extent << (ISOFS_BLOCK_BITS - bufbits);
517 if (!(bh = bread(parent->i_dev, block, bufsize))) return -1;
518
519 while (1 == 1) {
520 de = (struct iso_directory_record *) (bh->b_data + offset);
521 if (*((unsigned char *) de) == 0)
522 {
523 brelse(bh);
524 return -1;
525 }
526
527 offset += *((unsigned char *) de);
528
529 if (offset >= bufsize)
530 {
531 printk(".. Directory not in first block"
532 " of directory.\n");
533 brelse(bh);
534 return -1;
535 }
536
537 if (de->name_len[0] == 1 && de->name[0] == 1)
538 {
539 parent_dir = find_rock_ridge_relocation(de, parent);
540 brelse(bh);
541 break;
542 }
543 }
544 #ifdef DEBUG
545 printk("Parent dir:%x\n",parent_dir);
546 #endif
547
548
549
550
551 result = -1;
552
553 offset = 0;
554 block = parent_dir << (ISOFS_BLOCK_BITS - bufbits);
555 if (!block || !(bh = bread(parent->i_dev,block, bufsize)))
556 return -1;
557
558 for(;;)
559 {
560 de = (struct iso_directory_record *) (bh->b_data + offset);
561 inode_number = (block << bufbits)+(offset & (bufsize - 1));
562
563
564
565
566
567 if (*((unsigned char *) de) == 0)
568 {
569 brelse(bh);
570 offset = 0;
571 block++;
572 if(block & 1) return -1;
573 if (!block
574 || !(bh = bread(parent->i_dev,block, bufsize)))
575 return -1;
576 continue;
577 }
578
579
580
581
582
583 old_offset = offset;
584 offset += *((unsigned char *) de);
585
586 if (offset >= bufsize)
587 {
588 if((block & 1) != 0) return -1;
589 cpnt = kmalloc(1<<ISOFS_BLOCK_BITS,GFP_KERNEL);
590 memcpy(cpnt, bh->b_data, bufsize);
591 de = (struct iso_directory_record *)
592 ((char *)cpnt + old_offset);
593 brelse(bh);
594 offset -= bufsize;
595 block++;
596 if (!(bh = bread(parent->i_dev,block,bufsize))) {
597 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
598 return -1;
599 };
600 memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
601 }
602
603 if (find_rock_ridge_relocation(de, parent) == extent){
604 result = inode_number;
605 goto out;
606 }
607
608 if (cpnt) {
609 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
610 cpnt = NULL;
611 }
612 }
613
614
615
616
617 out:
618 if (cpnt) {
619 kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
620 cpnt = NULL;
621 }
622 brelse(bh);
623 #ifdef DEBUG
624 printk("Resultant Inode %d\n",result);
625 #endif
626 return result;
627 }
628
629 #ifdef LEAK_CHECK
630 #undef malloc
631 #undef free_s
632 #undef bread
633 #undef brelse
634
635 void * leak_check_malloc(unsigned int size){
636 void * tmp;
637 check_malloc++;
638 tmp = kmalloc(size, GFP_KERNEL);
639 return tmp;
640 }
641
642 void leak_check_free_s(void * obj, int size){
643 check_malloc--;
644 return kfree_s(obj, size);
645 }
646
647 struct buffer_head * leak_check_bread(int dev, int block, int size){
648 check_bread++;
649 return bread(dev, block, size);
650 }
651
652 void leak_check_brelse(struct buffer_head * bh){
653 check_bread--;
654 return brelse(bh);
655 }
656
657 #endif