Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / fs / iso9660 / iso9660_mount.c
1 /*
2  *
3  * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu>
4  *
5  * This file has been copied from EMILE, http://emile.sf.net
6  *
7  * some parts from mkisofs (c) J. Schilling
8  *
9  */
10
11 #include "libiso9660.h"
12 #include "libopenbios/bindings.h"
13 #include "libc/diskio.h"
14
15 void iso9660_name(iso9660_VOLUME *volume, struct iso_directory_record *idr, char *buffer)
16 {
17         int     j;
18         unsigned char ul, uc;
19
20         buffer[0] = 0;
21         if (idr->name_len[0] == 1 && idr->name[0] == 0)
22                 strcpy(buffer, ".");
23         else if (idr->name_len[0] == 1 && idr->name[0] == 1)
24                 strcpy(buffer, "..");
25         else {
26                 switch (volume->ucs_level) {
27                 case 3:
28                 case 2:
29                 case 1:
30                         /*
31                          * Unicode name.
32                          */
33
34                         for (j = 0; j < (int)idr->name_len[0] / 2; j++) {
35                                 ul = idr->name[j*2+1];
36
37                                 /*
38                                  * unicode convertion
39                                  * up = unls->unls_uni2cs[uh];
40                                  *
41                                  * if (up == NULL)
42                                  *      uc = '\0';
43                                  * else
44                                  *      uc = up[ul];
45                                  *
46                                  * we use only low byte
47                                  */
48
49                                 uc = ul;
50
51                                 buffer[j] = uc ? uc : '_';
52                         }
53                         buffer[idr->name_len[0]/2] = '\0';
54                         break;
55                 case 0:
56                         /*
57                          * Normal non-Unicode name.
58                          */
59                         strncpy(buffer, idr->name, idr->name_len[0]);
60                         buffer[idr->name_len[0]] = 0;
61                         break;
62                 default:
63                         /*
64                          * Don't know how to do these yet.  Maybe they are the same
65                          * as one of the above.
66                          */
67                         break;
68                 }
69         }
70 }
71
72 iso9660_VOLUME *iso9660_mount(int fd)
73 {
74         iso9660_VOLUME* volume;
75         struct iso_primary_descriptor *jpd;
76         struct iso_primary_descriptor ipd;
77         int     block;
78         int ucs_level = 0;
79
80         /* read filesystem descriptor */
81
82         seek_io(fd, 16 * ISOFS_BLOCK_SIZE);
83         read_io(fd, &ipd, sizeof (ipd));
84
85         /*
86          * High sierra:
87          *
88          *      DESC TYPE       == 1 (VD_SFS)   offset 8        len 1
89          *      STR ID          == "CDROM"      offset 9        len 5
90          *      STD_VER         == 1            offset 14       len 1
91          */
92
93         /* High Sierra format ? */
94
95         if ((((char *)&ipd)[8] == 1) &&
96             (strncmp(&((char *)&ipd)[9], "CDROM", 5) == 0) &&
97             (((char *)&ipd)[14] == 1)) {
98                 printk("Incompatible format: High Sierra format\n");
99                 return NULL;
100         }
101
102         /*
103          * ISO 9660:
104          *
105          *      DESC TYPE       == 1 (VD_PVD)   offset 0        len 1
106          *      STR ID          == "CD001"      offset 1        len 5
107          *      STD_VER         == 1            offset 6        len 1
108          */
109
110         /* NOT ISO 9660 format ? */
111
112         if ((ipd.type[0] != ISO_VD_PRIMARY) ||
113             (strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
114             (ipd.version[0] != 1)) {
115                 return NULL;
116         }
117
118         /* UCS info */
119
120         block = 16;
121
122         jpd = (struct iso_primary_descriptor *)
123                 malloc(sizeof(struct iso_primary_descriptor));
124         if (jpd == NULL)
125                 return NULL;
126
127         memcpy(jpd, &ipd, sizeof (ipd));
128         while ((uint8_t)jpd->type[0] != ISO_VD_END) {
129
130                 /*
131                  * If Joliet UCS escape sequence found, we may be wrong
132                  */
133
134                 if (jpd->unused3[0] == '%' &&
135                     jpd->unused3[1] == '/' &&
136                     (jpd->unused3[3] == '\0' ||
137                     jpd->unused3[3] == ' ') &&
138                     (jpd->unused3[2] == '@' ||
139                     jpd->unused3[2] == 'C' ||
140                     jpd->unused3[2] == 'E')) {
141
142                         if (jpd->version[0] != 1)
143                                 break;
144                 }
145
146                 block++;
147                 seek_io(fd, block * ISOFS_BLOCK_SIZE);
148                 read_io(fd, jpd, sizeof (*jpd));
149         }
150
151         ucs_level = 0;
152         if (((unsigned char) jpd->type[0] == ISO_VD_END)) {
153                 memcpy(jpd, &ipd, sizeof (ipd));
154         } else {
155                 switch (jpd->unused3[2]) {
156                 case '@':
157                         ucs_level = 1;
158                         break;
159                 case 'C':
160                         ucs_level = 2;
161                         break;
162                 case 'E':
163                         ucs_level = 3;
164                         break;
165                 }
166
167                 if (ucs_level && jpd->unused3[3] == ' ')
168                         printk("Warning: Joliet escape sequence uses illegal space at offset 3\n");
169         }
170
171         volume = (iso9660_VOLUME*)malloc(sizeof(iso9660_VOLUME));
172         if (volume == NULL)
173                 return NULL;
174
175         volume->descriptor = jpd;
176         volume->ucs_level = ucs_level;
177         volume->fd = fd;
178
179         return volume;
180 }
181
182 int iso9660_umount(iso9660_VOLUME* volume)
183 {
184         if (volume == NULL)
185                 return -1;
186         free(volume->descriptor);
187         free(volume);
188         return 0;
189 }
190
191 int iso9660_probe(int fd, long long offset)
192 {
193         struct iso_primary_descriptor ipd;
194
195         seek_io(fd, 16 * ISOFS_BLOCK_SIZE + offset);
196         read_io(fd, &ipd, sizeof (ipd));
197
198         if ((ipd.type[0] != ISO_VD_PRIMARY) ||
199             (strncmp(ipd.id, ISO_STANDARD_ID, sizeof (ipd.id)) != 0) ||
200             (ipd.version[0] != 1)) {
201                 return 0;
202         }
203
204         return -1;
205 }
206
207 struct iso_directory_record *iso9660_get_root_node(iso9660_VOLUME* volume)
208 {
209         return (struct iso_directory_record *)volume->descriptor->root_directory_record;
210 }