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