25150e5efe990aa73807f0f885c7bda9bc8d822c
[lunaix-os.git] / lunaix-os / kernel / fs / iso9660 / mount.c
1 #include <lunaix/block.h>
2 #include <lunaix/fs.h>
3 #include <lunaix/fs/iso9660.h>
4 #include <lunaix/mm/valloc.h>
5 #include <lunaix/spike.h>
6
7 #include <lunaix/mm/cake.h>
8
9 struct cake_pile* drec_cache_pile;
10
11 extern void
12 iso9660_init_inode(struct v_superblock* vsb, struct v_inode* inode);
13
14 u32_t
15 iso9660_rd_capacity(struct v_superblock* vsb)
16 {
17     struct iso_superblock* isovsb = (struct iso_superblock*)vsb->data;
18     return isovsb->volume_size;
19 }
20
21 int
22 iso9660_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
23 {
24     struct device* dev = vsb->dev;
25     struct iso_vol* vdesc = (struct iso_vol*)valloc(ISO9660_BLKSZ);
26     struct iso_vol_primary* vprim = NULL;
27     u32_t lba = 16;
28     int errno = 0;
29     do {
30         errno = dev->ops.read(dev, vdesc, ISO9660_BLKSZ * lba, ISO9660_BLKSZ);
31         if (errno < 0) {
32             errno = EIO;
33             goto done;
34         }
35         if (*(u32_t*)vdesc->std_id != ISO_SIGNATURE_LO) {
36             errno = ENODEV;
37             goto done;
38         }
39         if (vdesc->type == ISO_VOLPRIM) {
40             vprim = (struct iso_vol_primary*)vdesc;
41             break;
42         }
43         lba++;
44     } while (vdesc->type != ISO_VOLTERM);
45
46     if (!vprim) {
47         errno = EINVAL;
48         goto done;
49     }
50
51     struct iso_superblock* isovsb = valloc(sizeof(*isovsb));
52     isovsb->lb_size = vprim->lb_size.le;
53     isovsb->volume_size = vprim->vol_size.le * isovsb->lb_size;
54
55     vsb->data = isovsb;
56     vsb->ops.init_inode = iso9660_init_inode;
57     vsb->ops.read_capacity = iso9660_rd_capacity;
58     vsb->blksize = ISO9660_BLKSZ;
59
60     struct v_inode* rootino = vfs_i_alloc(vsb);
61     struct iso_var_mdu* mdu = (struct iso_var_mdu*)vprim->root_record;
62     struct iso_drecord* dir = iso9660_get_drecord(mdu);
63
64     if (!dir) {
65         vfree(isovsb);
66         errno = EINVAL;
67         goto done;
68     }
69
70     struct iso_drecache drecache;
71     iso9660_fill_drecache(&drecache, dir, mdu->len);
72
73     if ((errno = iso9660_fill_inode(rootino, &drecache, 0)) < 0) {
74         vfree(isovsb);
75         errno = EINVAL;
76         goto done;
77     }
78
79     if ((errno = iso9660_setup_dnode(mount_point, rootino)) < 0) {
80         vfree(isovsb);
81         errno = EINVAL;
82         goto done;
83     }
84
85     vfs_i_addhash(rootino);
86     return 0;
87
88 done:
89     vfree(vdesc);
90     return errno;
91 }
92
93 int
94 iso9660_unmount(struct v_superblock* vsb)
95 {
96     vfree(vsb->data);
97
98     return 0;
99 }
100
101 void
102 iso9660_init()
103 {
104     drec_cache_pile =
105       cake_new_pile("iso_drec", sizeof(struct iso_drecache), 1, 0);
106
107     struct filesystem* fs = fsm_new_fs("iso9660", -1);
108     fs->types |= FSTYPE_ROFS;
109     fs->mount = iso9660_mount;
110     fs->unmount = iso9660_unmount;
111
112     fsm_register(fs);
113 }
114 EXPORT_FILE_SYSTEM(iso9660, iso9660_init);