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