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