blob: 148587b3b0f593550f52dde4a8c1ea8c642378f3 [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
2 * Copyright (C) 1999 by Andries Brouwer
3 * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o
4 * Copyright (C) 2001 by Andreas Dilger
5 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
7 *
8 * Inspired also by libvolume_id by
9 * Kay Sievers <kay.sievers@vrfy.org>
10 *
11 * This file may be redistributed under the terms of the
12 * GNU Lesser General Public License.
13 */
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <string.h>
18#include <stdint.h>
19#include <ctype.h>
20
21#include "superblocks.h"
22
23struct iso9660_date {
24 unsigned char year[4];
25 unsigned char month[2];
26 unsigned char day[2];
27 unsigned char hour[2];
28 unsigned char minute[2];
29 unsigned char second[2];
30 unsigned char hundredth[2];
31 unsigned char offset;
32} __attribute__ ((packed));
33
34/* PVD - Primary volume descriptor */
35struct iso_volume_descriptor {
36 unsigned char vd_type;
37 unsigned char vd_id[5];
38 unsigned char vd_version;
39 unsigned char flags;
40 unsigned char system_id[32];
41 unsigned char volume_id[32];
42 unsigned char unused[8];
43 unsigned char space_size[8];
44 unsigned char escape_sequences[8];
45 unsigned char unused1[222];
46 unsigned char publisher_id[128];
47 unsigned char unused2[128];
48 unsigned char application_id[128];
49 unsigned char unused3[111];
50 struct iso9660_date created;
51 struct iso9660_date modified;
52} __attribute__((packed));
53
54/* Boot Record */
55struct boot_record {
56 unsigned char vd_type;
57 unsigned char vd_id[5];
58 unsigned char vd_version;
59 unsigned char boot_system_id[32];
60 unsigned char boot_id[32];
61 unsigned char unused[1];
62} __attribute__((packed));
63
64#define ISO_SUPERBLOCK_OFFSET 0x8000
65#define ISO_SECTOR_SIZE 0x800
66#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
67#define ISO_VD_BOOT_RECORD 0x0
68#define ISO_VD_SUPPLEMENTARY 0x2
69#define ISO_VD_END 0xff
70#define ISO_VD_MAX 16
71
72struct high_sierra_volume_descriptor {
73 unsigned char foo[8];
74 unsigned char type;
75 unsigned char id[5];
76 unsigned char version;
77 unsigned char unused1;
78 unsigned char system_id[32];
79 unsigned char volume_id[32];
80} __attribute__((packed));
81
82/* returns 1 if the begin of @ascii is equal to @utf16 string.
83 */
84static int ascii_eq_utf16be(unsigned char *ascii,
85 unsigned char *utf16, size_t len)
86{
87 size_t a, u;
88
89 for (a = 0, u = 0; u < len; a++, u += 2) {
90 if (utf16[u] != 0x0 || ascii[a] != utf16[u + 1])
91 return 0;
92 }
93 return 1;
94}
95
96/* old High Sierra format */
97static int probe_iso9660_hsfs(blkid_probe pr, const struct blkid_idmag *mag)
98{
99 struct high_sierra_volume_descriptor *iso;
100
101 iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor);
102 if (!iso)
103 return -1;
104
105 blkid_probe_set_version(pr, "High Sierra");
106 blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id));
107 return 0;
108}
109
110static int probe_iso9660_set_uuid (blkid_probe pr, const struct iso9660_date *date)
111{
112 unsigned char buffer[16];
113 unsigned int i, zeros = 0;
114
115 buffer[0] = date->year[0];
116 buffer[1] = date->year[1];
117 buffer[2] = date->year[2];
118 buffer[3] = date->year[3];
119 buffer[4] = date->month[0];
120 buffer[5] = date->month[1];
121 buffer[6] = date->day[0];
122 buffer[7] = date->day[1];
123 buffer[8] = date->hour[0];
124 buffer[9] = date->hour[1];
125 buffer[10] = date->minute[0];
126 buffer[11] = date->minute[1];
127 buffer[12] = date->second[0];
128 buffer[13] = date->second[1];
129 buffer[14] = date->hundredth[0];
130 buffer[15] = date->hundredth[1];
131
132 /* count the number of zeros ('0') in the date buffer */
133 for (i = 0, zeros = 0; i < sizeof(buffer); i++)
134 if (buffer[i] == '0')
135 zeros++;
136
137 /* due to the iso9660 standard if all date fields are '0' and offset is 0, the date is unset */
138 if (zeros == sizeof(buffer) && date->offset == 0)
139 return 0;
140
141 /* generate an UUID using this date and return success */
142 blkid_probe_sprintf_uuid (pr, buffer, sizeof(buffer),
143 "%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
144 buffer[0], buffer[1], buffer[2], buffer[3],
145 buffer[4], buffer[5],
146 buffer[6], buffer[7],
147 buffer[8], buffer[9],
148 buffer[10], buffer[11],
149 buffer[12], buffer[13],
150 buffer[14], buffer[15]);
151
152 return 1;
153}
154
155static int is_str_empty(const unsigned char *str, size_t len)
156{
157 size_t i;
158
159 if (!str || !*str)
160 return 1;
161
162 for (i = 0; i < len; i++)
163 if (!isspace(str[i]))
164 return 0;
165 return 1;
166}
167
168/* iso9660 [+ Microsoft Joliet Extension] */
169int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag)
170{
171 struct iso_volume_descriptor *iso;
172 unsigned char label[32];
173 int i;
174 int off;
175
176 if (strcmp(mag->magic, "CDROM") == 0)
177 return probe_iso9660_hsfs(pr, mag);
178
179 iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor);
180 if (!iso)
181 return -1;
182
183 memcpy(label, iso->volume_id, sizeof(label));
184
185 if (!is_str_empty(iso->system_id, sizeof(iso->system_id)))
186 blkid_probe_set_id_label(pr, "SYSTEM_ID",
187 iso->system_id, sizeof(iso->system_id));
188
189 if (!is_str_empty(iso->publisher_id, sizeof(iso->publisher_id)))
190 blkid_probe_set_id_label(pr, "PUBLISHER_ID",
191 iso->publisher_id, sizeof(iso->publisher_id));
192
193 if (!is_str_empty(iso->application_id, sizeof(iso->application_id)))
194 blkid_probe_set_id_label(pr, "APPLICATION_ID",
195 iso->application_id, sizeof(iso->application_id));
196
197 /* create an UUID using the modified/created date */
198 if (! probe_iso9660_set_uuid(pr, &iso->modified))
199 probe_iso9660_set_uuid(pr, &iso->created);
200
201 /* Joliet Extension and Boot Record */
202 off = ISO_VD_OFFSET;
203 for (i = 0; i < ISO_VD_MAX; i++) {
204 struct boot_record *boot= (struct boot_record *)
205 blkid_probe_get_buffer(pr,
206 off,
207 max(sizeof(struct boot_record),
208 sizeof(struct iso_volume_descriptor)));
209
210 if (boot == NULL || boot->vd_type == ISO_VD_END)
211 break;
212
213 if (boot->vd_type == ISO_VD_BOOT_RECORD) {
214 if (!is_str_empty(boot->boot_system_id,
215 sizeof(boot->boot_system_id)))
216 blkid_probe_set_id_label(pr, "BOOT_SYSTEM_ID",
217 boot->boot_system_id,
218 sizeof(boot->boot_system_id));
219 off += ISO_SECTOR_SIZE;
220 continue;
221 }
222
223 /* Not a Boot record, lets see if its supplemntary volume descriptor */
224 iso = (struct iso_volume_descriptor *) boot;
225
226 if (iso->vd_type != ISO_VD_SUPPLEMENTARY) {
227 off += ISO_SECTOR_SIZE;
228 continue;
229 }
230
231 if (memcmp(iso->escape_sequences, "%/@", 3) == 0 ||
232 memcmp(iso->escape_sequences, "%/C", 3) == 0 ||
233 memcmp(iso->escape_sequences, "%/E", 3) == 0) {
234
235 blkid_probe_set_version(pr, "Joliet Extension");
236
237 /* Is the Joliet (UTF16BE) label equal to the label in
238 * the PVD? If yes, use PVD label. The Jolied version
239 * of the label could be trimed (because UTF16..).
240 */
241 if (ascii_eq_utf16be(label, iso->volume_id, 32))
242 break;
243
244 blkid_probe_set_utf8label(pr,
245 iso->volume_id,
246 sizeof(iso->volume_id),
247 BLKID_ENC_UTF16BE);
248 goto has_label;
249 }
250 off += ISO_SECTOR_SIZE;
251 }
252
253 /* Joliet not found, let use standard iso label */
254 blkid_probe_set_label(pr, label, sizeof(label));
255
256has_label:
257 return 0;
258}
259
260const struct blkid_idinfo iso9660_idinfo =
261{
262 .name = "iso9660",
263 .usage = BLKID_USAGE_FILESYSTEM,
264 .probefunc = probe_iso9660,
265 .flags = BLKID_IDINFO_TOLERANT,
266 .magics =
267 {
268 { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 },
269 { .magic = "CDROM", .len = 5, .kboff = 32, .sboff = 9 },
270 { NULL }
271 }
272};
273