/src/util-linux/libblkid/src/superblocks/iso9660.c
Line | Count | Source |
1 | | /* |
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 | | #include "cctype.h" |
23 | | #include "iso9660.h" |
24 | | |
25 | | struct hs_date { |
26 | | unsigned char year[4]; |
27 | | unsigned char month[2]; |
28 | | unsigned char day[2]; |
29 | | unsigned char hour[2]; |
30 | | unsigned char minute[2]; |
31 | | unsigned char second[2]; |
32 | | unsigned char hundredth[2]; |
33 | | } __attribute__ ((packed)); |
34 | | |
35 | | struct iso9660_date { |
36 | | struct hs_date common; |
37 | | unsigned char offset; |
38 | | } __attribute__ ((packed)); |
39 | | |
40 | | /* PVD - Primary volume descriptor */ |
41 | | struct iso_volume_descriptor { |
42 | | /* High Sierra has 8 bytes before descriptor with Volume Descriptor LBN value, those are skipped by blkid_probe_get_buffer() */ |
43 | | unsigned char vd_type; |
44 | | unsigned char vd_id[5]; |
45 | | unsigned char vd_version; |
46 | | unsigned char flags; |
47 | | unsigned char system_id[32]; |
48 | | unsigned char volume_id[32]; |
49 | | unsigned char unused[8]; |
50 | | unsigned char space_size[8]; |
51 | | unsigned char escape_sequences[32]; |
52 | | unsigned char set_size[4]; |
53 | | unsigned char vol_seq_num[4]; |
54 | | unsigned char logical_block_size[4]; |
55 | | unsigned char path_table_size[8]; |
56 | | union { |
57 | | struct { |
58 | | unsigned char type_l_path_table[4]; |
59 | | unsigned char opt_type_l_path_table[4]; |
60 | | unsigned char type_m_path_table[4]; |
61 | | unsigned char opt_type_m_path_table[4]; |
62 | | unsigned char root_dir_record[34]; |
63 | | unsigned char volume_set_id[128]; |
64 | | unsigned char publisher_id[128]; |
65 | | unsigned char data_preparer_id[128]; |
66 | | unsigned char application_id[128]; |
67 | | unsigned char copyright_file_id[37]; |
68 | | unsigned char abstract_file_id[37]; |
69 | | unsigned char bibliographic_file_id[37]; |
70 | | struct iso9660_date created; |
71 | | struct iso9660_date modified; |
72 | | struct iso9660_date expiration; |
73 | | struct iso9660_date effective; |
74 | | unsigned char std_version; |
75 | | } iso; /* ISO9660 */ |
76 | | struct { |
77 | | unsigned char type_l_path_table[4]; |
78 | | unsigned char opt1_type_l_path_table[4]; |
79 | | unsigned char opt2_type_l_path_table[4]; |
80 | | unsigned char opt3_type_l_path_table[4]; |
81 | | unsigned char type_m_path_table[4]; |
82 | | unsigned char opt1_type_m_path_table[4]; |
83 | | unsigned char opt2_type_m_path_table[4]; |
84 | | unsigned char opt3_type_m_path_table[4]; |
85 | | unsigned char root_dir_record[34]; |
86 | | unsigned char volume_set_id[128]; |
87 | | unsigned char publisher_id[128]; |
88 | | unsigned char data_preparer_id[128]; |
89 | | unsigned char application_id[128]; |
90 | | unsigned char copyright_file_id[32]; |
91 | | unsigned char abstract_file_id[32]; |
92 | | struct hs_date created; |
93 | | struct hs_date modified; |
94 | | struct hs_date expiration; |
95 | | struct hs_date effective; |
96 | | unsigned char std_version; |
97 | | } hs; /* High Sierra */ |
98 | | }; |
99 | | } __attribute__((packed)); |
100 | | |
101 | | /* Boot Record */ |
102 | | struct boot_record { |
103 | | /* High Sierra has 8 bytes before descriptor with Volume Descriptor LBN value, those are skipped by blkid_probe_get_buffer() */ |
104 | | unsigned char vd_type; |
105 | | unsigned char vd_id[5]; |
106 | | unsigned char vd_version; |
107 | | unsigned char boot_system_id[32]; |
108 | | unsigned char boot_id[32]; |
109 | | unsigned char unused[1]; |
110 | | } __attribute__((packed)); |
111 | | |
112 | 477 | #define ISO_SUPERBLOCK_OFFSET 0x8000 |
113 | 6.18k | #define ISO_SECTOR_SIZE 0x800 |
114 | 2.36k | #define ISO_VD_BOOT_RECORD 0x0 |
115 | 4.26k | #define ISO_VD_PRIMARY 0x1 |
116 | 3.59k | #define ISO_VD_SUPPLEMENTARY 0x2 |
117 | 5.79k | #define ISO_VD_END 0xff |
118 | 12.3k | #define ISO_VD_MAX 16 |
119 | | /* maximal string field size used anywhere in ISO; update if necessary */ |
120 | | #define ISO_MAX_FIELDSIZ sizeof_member(struct iso_volume_descriptor, iso.volume_set_id) |
121 | | |
122 | | static int probe_iso9660_set_uuid (blkid_probe pr, const struct hs_date *date, unsigned char offset) |
123 | 64 | { |
124 | 64 | unsigned char buffer[16]; |
125 | 64 | unsigned int i, zeros = 0; |
126 | | |
127 | 64 | buffer[0] = date->year[0]; |
128 | 64 | buffer[1] = date->year[1]; |
129 | 64 | buffer[2] = date->year[2]; |
130 | 64 | buffer[3] = date->year[3]; |
131 | 64 | buffer[4] = date->month[0]; |
132 | 64 | buffer[5] = date->month[1]; |
133 | 64 | buffer[6] = date->day[0]; |
134 | 64 | buffer[7] = date->day[1]; |
135 | 64 | buffer[8] = date->hour[0]; |
136 | 64 | buffer[9] = date->hour[1]; |
137 | 64 | buffer[10] = date->minute[0]; |
138 | 64 | buffer[11] = date->minute[1]; |
139 | 64 | buffer[12] = date->second[0]; |
140 | 64 | buffer[13] = date->second[1]; |
141 | 64 | buffer[14] = date->hundredth[0]; |
142 | 64 | buffer[15] = date->hundredth[1]; |
143 | | |
144 | | /* count the number of zeros ('0') in the date buffer */ |
145 | 1.08k | for (i = 0, zeros = 0; i < sizeof(buffer); i++) |
146 | 1.02k | if (buffer[i] == '0') |
147 | 221 | zeros++; |
148 | | |
149 | | /* due to the iso9660 standard if all date fields are '0' and offset is 0, the date is unset */ |
150 | 64 | if (zeros == sizeof(buffer) && offset == 0) |
151 | 7 | return 0; |
152 | | |
153 | | /* generate an UUID using this date and return success */ |
154 | 57 | blkid_probe_sprintf_uuid (pr, buffer, sizeof(buffer), |
155 | 57 | "%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c", |
156 | 57 | buffer[0], buffer[1], buffer[2], buffer[3], |
157 | 57 | buffer[4], buffer[5], |
158 | 57 | buffer[6], buffer[7], |
159 | 57 | buffer[8], buffer[9], |
160 | 57 | buffer[10], buffer[11], |
161 | 57 | buffer[12], buffer[13], |
162 | 57 | buffer[14], buffer[15]); |
163 | | |
164 | 57 | return 1; |
165 | 64 | } |
166 | | |
167 | | static int is_str_empty(const unsigned char *str, size_t len) |
168 | 177 | { |
169 | 177 | size_t i; |
170 | | |
171 | 177 | if (!str || !*str) |
172 | 50 | return 1; |
173 | | |
174 | 1.84k | for (i = 0; i < len; i++) |
175 | 1.83k | if (!isspace(str[i])) |
176 | 121 | return 0; |
177 | 6 | return 1; |
178 | 127 | } |
179 | | |
180 | | static int is_utf16be_str_empty(unsigned char *utf16, size_t len) |
181 | 54 | { |
182 | 54 | size_t i; |
183 | | |
184 | 54 | for (i = 0; i < len; i += 2) { |
185 | 54 | if (utf16[i] != 0x0 || !isspace(utf16[i + 1])) |
186 | 54 | return 0; |
187 | 54 | } |
188 | 0 | return 1; |
189 | 54 | } |
190 | | |
191 | | /* if @utf16 is prefix of @ascii (ignoring non-representable characters and upper-case conversion) |
192 | | * then reconstruct prefix from @utf16 and @ascii, append suffix from @ascii, fill it into @out |
193 | | * and returns length of bytes written into @out; otherwise returns zero */ |
194 | | static size_t merge_utf16be_ascii(unsigned char *out, size_t out_len, const unsigned char *utf16, const unsigned char *ascii, size_t len) |
195 | 89 | { |
196 | 89 | size_t o, a, u; |
197 | | |
198 | 111 | for (o = 0, a = 0, u = 0; u + 1 < len && a < len && o + 1 < out_len; o += 2, a++, u += 2) { |
199 | | /* Surrogate pair with code point above U+FFFF */ |
200 | 111 | if (utf16[u] >= 0xD8 && utf16[u] <= 0xDB && u + 3 < len && |
201 | 1 | utf16[u + 2] >= 0xDC && utf16[u + 2] <= 0xDF) { |
202 | 0 | out[o++] = utf16[u++]; |
203 | 0 | out[o++] = utf16[u++]; |
204 | 0 | } |
205 | | /* Value '_' is replacement for non-representable character */ |
206 | 111 | if (ascii[a] == '_') { |
207 | 0 | out[o] = utf16[u]; |
208 | 0 | out[o + 1] = utf16[u + 1]; |
209 | 111 | } else if (utf16[u] == 0x00 && utf16[u + 1] == '_') { |
210 | 0 | out[o] = 0x00; |
211 | 0 | out[o + 1] = ascii[a]; |
212 | 111 | } else if (utf16[u] == 0x00 && c_toupper(ascii[a]) == c_toupper(utf16[u + 1])) { |
213 | 22 | out[o] = 0x00; |
214 | 22 | out[o + 1] = c_isupper(ascii[a]) ? utf16[u + 1] : ascii[a]; |
215 | 89 | } else { |
216 | 89 | return 0; |
217 | 89 | } |
218 | 111 | } |
219 | | |
220 | 0 | for (; a < len && o + 1 < out_len; o += 2, a++) { |
221 | 0 | out[o] = 0x00; |
222 | 0 | out[o + 1] = ascii[a]; |
223 | 0 | } |
224 | |
|
225 | 0 | return o; |
226 | 89 | } |
227 | | |
228 | | /* iso9660 [+ Microsoft Joliet Extension] */ |
229 | | static int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag) |
230 | 477 | { |
231 | 477 | struct boot_record *boot = NULL; |
232 | 477 | struct iso_volume_descriptor *pvd = NULL; |
233 | 477 | struct iso_volume_descriptor *joliet = NULL; |
234 | | /* space for merge_utf16be_ascii(ISO_ID_BUFSIZ bytes) */ |
235 | 477 | unsigned char buf[ISO_MAX_FIELDSIZ * 5 / 2]; |
236 | 477 | const struct hs_date *modified; |
237 | 477 | const struct hs_date *created; |
238 | 477 | unsigned char modified_offset; |
239 | 477 | unsigned char created_offset; |
240 | 477 | size_t len; |
241 | 477 | int is_hs; |
242 | 477 | int is_unicode_empty; |
243 | 477 | int is_ascii_hs_empty; |
244 | 477 | int is_ascii_iso_empty; |
245 | 477 | int i; |
246 | 477 | uint64_t off; |
247 | | |
248 | 477 | if (blkid_probe_get_hint(pr, mag->hoff, &off) < 0) |
249 | 477 | off = 0; |
250 | | |
251 | 477 | if (off % ISO_SECTOR_SIZE) |
252 | 0 | return 1; |
253 | | |
254 | 477 | is_hs = (strcmp(mag->magic, "CDROM") == 0); |
255 | | |
256 | 6.18k | for (i = 0, off += ISO_SUPERBLOCK_OFFSET; i < ISO_VD_MAX && (!boot || !pvd || (!is_hs && !joliet)); i++, off += ISO_SECTOR_SIZE) { |
257 | 5.79k | const unsigned char *desc = |
258 | 5.79k | blkid_probe_get_buffer(pr, |
259 | 5.79k | off + (is_hs ? 8 : 0), /* High Sierra has 8 bytes before descriptor with Volume Descriptor LBN value */ |
260 | 5.79k | max(sizeof(struct boot_record), |
261 | 5.79k | sizeof(struct iso_volume_descriptor))); |
262 | | |
263 | 5.79k | if (desc == NULL || desc[0] == ISO_VD_END) |
264 | 84 | break; |
265 | 5.71k | else if (!boot && desc[0] == ISO_VD_BOOT_RECORD) |
266 | 437 | boot = (struct boot_record *)desc; |
267 | 5.27k | else if (!pvd && desc[0] == ISO_VD_PRIMARY) |
268 | 311 | pvd = (struct iso_volume_descriptor *)desc; |
269 | 4.96k | else if (!is_hs && !joliet && desc[0] == ISO_VD_SUPPLEMENTARY) { |
270 | 474 | joliet = (struct iso_volume_descriptor *)desc; |
271 | 474 | if (memcmp(joliet->escape_sequences, "%/@", 3) != 0 && |
272 | 464 | memcmp(joliet->escape_sequences, "%/C", 3) != 0 && |
273 | 459 | memcmp(joliet->escape_sequences, "%/E", 3) != 0) |
274 | 429 | joliet = NULL; |
275 | 474 | } |
276 | 5.79k | } |
277 | | |
278 | 477 | if (!pvd) |
279 | 166 | return errno ? -errno : 1; |
280 | | |
281 | 311 | uint16_t logical_block_size = isonum_723(pvd->logical_block_size, false); |
282 | 311 | uint32_t space_size = isonum_733(pvd->space_size, false); |
283 | | |
284 | 311 | if (logical_block_size == 0) |
285 | 71 | return 1; |
286 | | |
287 | | /* |
288 | | * Verify the root directory record to reduce false positives. |
289 | | * |
290 | | * The CD001 magic at 32KB can match data content on other |
291 | | * filesystems (e.g. an .iso file stored on XFS). Validate that |
292 | | * the root directory extent actually contains a valid directory |
293 | | * entry -- the first entry must be the "." self-reference with |
294 | | * file_id = 0x00 pointing back to the same LBA. |
295 | | */ |
296 | 240 | { |
297 | 240 | const unsigned char *rdr = is_hs ? |
298 | 128 | pvd->hs.root_dir_record : pvd->iso.root_dir_record; |
299 | 240 | uint32_t root_lba = isonum_731(rdr + 2); |
300 | 240 | uint32_t root_len = isonum_731(rdr + 10); |
301 | 240 | uint64_t root_off = (uint64_t) root_lba * logical_block_size; |
302 | 240 | const unsigned char *rootdata; |
303 | | |
304 | 240 | if (root_len == 0) |
305 | 19 | return 1; |
306 | | |
307 | 221 | rootdata = blkid_probe_get_buffer(pr, root_off, |
308 | 221 | root_len < 2048 ? root_len : 2048); |
309 | 221 | if (!rootdata) |
310 | 66 | return errno ? -errno : 1; |
311 | | |
312 | | /* The first directory entry must be "." (self-reference): |
313 | | * - dr_len >= 34 (minimum directory record size) |
314 | | * - file_id_len == 1 |
315 | | * - file_id == 0x00 (the "." identifier) |
316 | | * - extent location == root_lba (points to itself) |
317 | | */ |
318 | 155 | if (rootdata[0] < 34 || |
319 | 136 | rootdata[32] != 1 || |
320 | 121 | rootdata[33] != 0x00 || |
321 | 118 | isonum_731(rootdata + 2) != root_lba) { |
322 | 96 | DBG(LOWPROBE, ul_debug("ISO9660: root dir validation " |
323 | 96 | "failed (false positive CD001 signature?)")); |
324 | 96 | return 1; |
325 | 96 | } |
326 | 155 | } |
327 | | |
328 | 59 | blkid_probe_set_fsblocksize(pr, logical_block_size); |
329 | 59 | blkid_probe_set_block_size(pr, logical_block_size); |
330 | 59 | blkid_probe_set_fssize(pr, (uint64_t) space_size * logical_block_size); |
331 | | |
332 | 59 | if (joliet && (len = merge_utf16be_ascii(buf, sizeof(buf), joliet->system_id, pvd->system_id, sizeof(pvd->system_id))) != 0) |
333 | 0 | blkid_probe_set_utf8_id_label(pr, "SYSTEM_ID", buf, len, UL_ENCODE_UTF16BE); |
334 | 59 | else if (joliet) |
335 | 18 | blkid_probe_set_utf8_id_label(pr, "SYSTEM_ID", joliet->system_id, sizeof(joliet->system_id), UL_ENCODE_UTF16BE); |
336 | 41 | else |
337 | 41 | blkid_probe_set_id_label(pr, "SYSTEM_ID", pvd->system_id, sizeof(pvd->system_id)); |
338 | | |
339 | 59 | if (joliet && (len = merge_utf16be_ascii(buf, sizeof(buf), joliet->iso.volume_set_id, pvd->iso.volume_set_id, sizeof(pvd->iso.volume_set_id))) != 0) |
340 | 0 | blkid_probe_set_utf8_id_label(pr, "VOLUME_SET_ID", buf, len, UL_ENCODE_UTF16BE); |
341 | 59 | else if (joliet) |
342 | 18 | blkid_probe_set_utf8_id_label(pr, "VOLUME_SET_ID", joliet->iso.volume_set_id, sizeof(joliet->iso.volume_set_id), UL_ENCODE_UTF16BE); |
343 | 41 | else if (is_hs) |
344 | 31 | blkid_probe_set_id_label(pr, "VOLUME_SET_ID", pvd->hs.volume_set_id, sizeof(pvd->hs.volume_set_id)); |
345 | 10 | else |
346 | 10 | blkid_probe_set_id_label(pr, "VOLUME_SET_ID", pvd->iso.volume_set_id, sizeof(pvd->iso.volume_set_id)); |
347 | | |
348 | 59 | is_ascii_hs_empty = (!is_hs || is_str_empty(pvd->hs.publisher_id, sizeof(pvd->hs.publisher_id)) || pvd->hs.publisher_id[0] == '_'); |
349 | 59 | is_ascii_iso_empty = (is_hs || is_str_empty(pvd->iso.publisher_id, sizeof(pvd->iso.publisher_id)) || pvd->iso.publisher_id[0] == '_'); |
350 | 59 | is_unicode_empty = (!joliet || is_utf16be_str_empty(joliet->iso.publisher_id, sizeof(joliet->iso.publisher_id)) || (joliet->iso.publisher_id[0] == 0x00 && joliet->iso.publisher_id[1] == '_')); |
351 | 59 | if (!is_unicode_empty && !is_ascii_iso_empty && (len = merge_utf16be_ascii(buf, sizeof(buf), joliet->iso.publisher_id, pvd->iso.publisher_id, sizeof(pvd->iso.publisher_id))) != 0) |
352 | 0 | blkid_probe_set_utf8_id_label(pr, "PUBLISHER_ID", buf, len, UL_ENCODE_UTF16BE); |
353 | 59 | else if (!is_unicode_empty) |
354 | 18 | blkid_probe_set_utf8_id_label(pr, "PUBLISHER_ID", joliet->iso.publisher_id, sizeof(joliet->iso.publisher_id), UL_ENCODE_UTF16BE); |
355 | 41 | else if (!is_ascii_hs_empty) |
356 | 17 | blkid_probe_set_id_label(pr, "PUBLISHER_ID", pvd->hs.publisher_id, sizeof(pvd->hs.publisher_id)); |
357 | 24 | else if (!is_ascii_iso_empty) |
358 | 9 | blkid_probe_set_id_label(pr, "PUBLISHER_ID", pvd->iso.publisher_id, sizeof(pvd->iso.publisher_id)); |
359 | | |
360 | 59 | is_ascii_hs_empty = (!is_hs || is_str_empty(pvd->hs.data_preparer_id, sizeof(pvd->hs.data_preparer_id)) || pvd->hs.data_preparer_id[0] == '_'); |
361 | 59 | is_ascii_iso_empty = (is_hs || is_str_empty(pvd->iso.data_preparer_id, sizeof(pvd->iso.data_preparer_id)) || pvd->iso.data_preparer_id[0] == '_'); |
362 | 59 | is_unicode_empty = (!joliet || is_utf16be_str_empty(joliet->iso.data_preparer_id, sizeof(joliet->iso.data_preparer_id)) || (joliet->iso.data_preparer_id[0] == 0x00 && joliet->iso.data_preparer_id[1] == '_')); |
363 | 59 | if (!is_unicode_empty && !is_ascii_iso_empty && (len = merge_utf16be_ascii(buf, sizeof(buf), joliet->iso.data_preparer_id, pvd->iso.data_preparer_id, sizeof(pvd->iso.data_preparer_id))) != 0) |
364 | 0 | blkid_probe_set_utf8_id_label(pr, "DATA_PREPARER_ID", buf, len, UL_ENCODE_UTF16BE); |
365 | 59 | else if (!is_unicode_empty) |
366 | 18 | blkid_probe_set_utf8_id_label(pr, "DATA_PREPARER_ID", joliet->iso.data_preparer_id, sizeof(joliet->iso.data_preparer_id), UL_ENCODE_UTF16BE); |
367 | 41 | else if (!is_ascii_hs_empty) |
368 | 21 | blkid_probe_set_id_label(pr, "DATA_PREPARER_ID", pvd->hs.data_preparer_id, sizeof(pvd->hs.data_preparer_id)); |
369 | 20 | else if (!is_ascii_iso_empty) |
370 | 9 | blkid_probe_set_id_label(pr, "DATA_PREPARER_ID", pvd->iso.data_preparer_id, sizeof(pvd->iso.data_preparer_id)); |
371 | | |
372 | 59 | is_ascii_hs_empty = (!is_hs || is_str_empty(pvd->hs.application_id, sizeof(pvd->hs.application_id)) || pvd->hs.application_id[0] == '_'); |
373 | 59 | is_ascii_iso_empty = (is_hs || is_str_empty(pvd->iso.application_id, sizeof(pvd->iso.application_id)) || pvd->iso.application_id[0] == '_'); |
374 | 59 | is_unicode_empty = (!joliet || is_utf16be_str_empty(joliet->iso.application_id, sizeof(joliet->iso.application_id)) || (joliet->iso.application_id[0] == 0x00 && joliet->iso.application_id[1] == '_')); |
375 | 59 | if (!is_unicode_empty && !is_ascii_iso_empty && (len = merge_utf16be_ascii(buf, sizeof(buf), joliet->iso.application_id, pvd->iso.application_id, sizeof(pvd->iso.application_id))) != 0) |
376 | 0 | blkid_probe_set_utf8_id_label(pr, "APPLICATION_ID", buf, len, UL_ENCODE_UTF16BE); |
377 | 59 | else if (!is_unicode_empty) |
378 | 18 | blkid_probe_set_utf8_id_label(pr, "APPLICATION_ID", joliet->iso.application_id, sizeof(joliet->iso.application_id), UL_ENCODE_UTF16BE); |
379 | 41 | else if (!is_ascii_hs_empty) |
380 | 23 | blkid_probe_set_id_label(pr, "APPLICATION_ID", pvd->hs.application_id, sizeof(pvd->hs.application_id)); |
381 | 18 | else if (!is_ascii_iso_empty) |
382 | 7 | blkid_probe_set_id_label(pr, "APPLICATION_ID", pvd->iso.application_id, sizeof(pvd->iso.application_id)); |
383 | | |
384 | 59 | if (is_hs) { |
385 | 31 | modified = &pvd->hs.modified; |
386 | 31 | created = &pvd->hs.created; |
387 | 31 | modified_offset = 0; |
388 | 31 | created_offset = 0; |
389 | 31 | } else { |
390 | 28 | modified = &pvd->iso.modified.common; |
391 | 28 | created = &pvd->iso.created.common; |
392 | 28 | modified_offset = pvd->iso.modified.offset; |
393 | 28 | created_offset = pvd->iso.created.offset; |
394 | 28 | } |
395 | | |
396 | | /* create an UUID using the modified/created date */ |
397 | 59 | if (! probe_iso9660_set_uuid(pr, modified, modified_offset)) |
398 | 5 | probe_iso9660_set_uuid(pr, created, created_offset); |
399 | | |
400 | 59 | if (boot) |
401 | 57 | blkid_probe_set_id_label(pr, "BOOT_SYSTEM_ID", |
402 | 57 | boot->boot_system_id, |
403 | 57 | sizeof(boot->boot_system_id)); |
404 | | |
405 | 59 | if (joliet) |
406 | 18 | blkid_probe_set_version(pr, "Joliet Extension"); |
407 | 41 | else if (is_hs) |
408 | 31 | blkid_probe_set_version(pr, "High Sierra"); |
409 | | |
410 | | /* Label in Joliet is UNICODE (UTF16BE) but can contain only 16 characters. Label in PVD is |
411 | | * subset of ASCII but can contain up to the 32 characters. Non-representable characters are |
412 | | * stored as replacement character '_'. Label in Joliet is in most cases trimmed but UNICODE |
413 | | * version of label in PVD. Based on these facts try to reconstruct original label if label |
414 | | * in Joliet is prefix of the label in PVD (ignoring non-representable characters). |
415 | | */ |
416 | 59 | if (joliet && (len = merge_utf16be_ascii(buf, sizeof(buf), joliet->volume_id, pvd->volume_id, sizeof(pvd->volume_id))) != 0) |
417 | 0 | blkid_probe_set_utf8label(pr, buf, len, UL_ENCODE_UTF16BE); |
418 | 59 | else if (joliet) |
419 | 18 | blkid_probe_set_utf8label(pr, joliet->volume_id, sizeof(joliet->volume_id), UL_ENCODE_UTF16BE); |
420 | 41 | else |
421 | 41 | blkid_probe_set_label(pr, pvd->volume_id, sizeof(pvd->volume_id)); |
422 | | |
423 | 59 | return 0; |
424 | 155 | } |
425 | | |
426 | | const struct blkid_idinfo iso9660_idinfo = |
427 | | { |
428 | | .name = "iso9660", |
429 | | .usage = BLKID_USAGE_FILESYSTEM, |
430 | | .probefunc = probe_iso9660, |
431 | | .flags = BLKID_IDINFO_TOLERANT, |
432 | | .magics = |
433 | | { |
434 | | /* |
435 | | * Due to different location of vd_id[] in ISO9660 and High Sierra, IS9660 can match |
436 | | * also High Sierra vd_id[]. So always check ISO9660 (CD001) before High Sierra (CDROM). |
437 | | */ |
438 | | { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1, .hoff = "session_offset" }, |
439 | | { .magic = "CDROM", .len = 5, .kboff = 32, .sboff = 9, .hoff = "session_offset" }, |
440 | | { NULL } |
441 | | } |
442 | | }; |
443 | | |