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>
8 * Inspired also by libvolume_id by
9 * Kay Sievers <kay.sievers@vrfy.org>
11 * This file may be redistributed under the terms of the
12 * GNU Lesser General Public License.
21 #include "superblocks.h"
25 unsigned char year
[4];
26 unsigned char month
[2];
28 unsigned char hour
[2];
29 unsigned char minute
[2];
30 unsigned char second
[2];
31 unsigned char hundredth
[2];
33 } __attribute__ ((packed
));
35 /* PVD - Primary volume descriptor */
36 struct iso_volume_descriptor
{
37 unsigned char vd_type
;
38 unsigned char vd_id
[5];
39 unsigned char vd_version
;
41 unsigned char system_id
[32];
42 unsigned char volume_id
[32];
43 unsigned char unused
[8];
44 unsigned char space_size
[8];
45 unsigned char escape_sequences
[8];
46 unsigned char unused1
[222];
47 unsigned char publisher_id
[128];
48 unsigned char unused2
[128];
49 unsigned char application_id
[128];
50 unsigned char unused3
[111];
51 struct iso9660_date created
;
52 struct iso9660_date modified
;
53 } __attribute__((packed
));
57 unsigned char vd_type
;
58 unsigned char vd_id
[5];
59 unsigned char vd_version
;
60 unsigned char boot_system_id
[32];
61 unsigned char boot_id
[32];
62 unsigned char unused
[1];
63 } __attribute__((packed
));
65 #define ISO_SUPERBLOCK_OFFSET 0x8000
66 #define ISO_SECTOR_SIZE 0x800
67 #define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
68 #define ISO_VD_BOOT_RECORD 0x0
69 #define ISO_VD_SUPPLEMENTARY 0x2
70 #define ISO_VD_END 0xff
73 struct high_sierra_volume_descriptor
{
77 unsigned char version
;
78 unsigned char unused1
;
79 unsigned char system_id
[32];
80 unsigned char volume_id
[32];
81 } __attribute__((packed
));
83 /* returns 1 if the begin of @ascii is equal to @utf16 string.
85 static int ascii_eq_utf16be(unsigned char *ascii
,
86 unsigned char *utf16
, size_t len
)
90 for (a
= 0, u
= 0; u
< len
; a
++, u
+= 2) {
91 if (utf16
[u
] != 0x0 || ascii
[a
] != utf16
[u
+ 1])
97 /* old High Sierra format */
98 static int probe_iso9660_hsfs(blkid_probe pr
, const struct blkid_idmag
*mag
)
100 struct high_sierra_volume_descriptor
*iso
;
102 iso
= blkid_probe_get_sb(pr
, mag
, struct high_sierra_volume_descriptor
);
104 return errno
? -errno
: 1;
106 blkid_probe_set_version(pr
, "High Sierra");
107 blkid_probe_set_label(pr
, iso
->volume_id
, sizeof(iso
->volume_id
));
111 static int probe_iso9660_set_uuid (blkid_probe pr
, const struct iso9660_date
*date
)
113 unsigned char buffer
[16];
114 unsigned int i
, zeros
= 0;
116 buffer
[0] = date
->year
[0];
117 buffer
[1] = date
->year
[1];
118 buffer
[2] = date
->year
[2];
119 buffer
[3] = date
->year
[3];
120 buffer
[4] = date
->month
[0];
121 buffer
[5] = date
->month
[1];
122 buffer
[6] = date
->day
[0];
123 buffer
[7] = date
->day
[1];
124 buffer
[8] = date
->hour
[0];
125 buffer
[9] = date
->hour
[1];
126 buffer
[10] = date
->minute
[0];
127 buffer
[11] = date
->minute
[1];
128 buffer
[12] = date
->second
[0];
129 buffer
[13] = date
->second
[1];
130 buffer
[14] = date
->hundredth
[0];
131 buffer
[15] = date
->hundredth
[1];
133 /* count the number of zeros ('0') in the date buffer */
134 for (i
= 0, zeros
= 0; i
< sizeof(buffer
); i
++)
135 if (buffer
[i
] == '0')
138 /* due to the iso9660 standard if all date fields are '0' and offset is 0, the date is unset */
139 if (zeros
== sizeof(buffer
) && date
->offset
== 0)
142 /* generate an UUID using this date and return success */
143 blkid_probe_sprintf_uuid (pr
, buffer
, sizeof(buffer
),
144 "%c%c%c%c-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
145 buffer
[0], buffer
[1], buffer
[2], buffer
[3],
146 buffer
[4], buffer
[5],
147 buffer
[6], buffer
[7],
148 buffer
[8], buffer
[9],
149 buffer
[10], buffer
[11],
150 buffer
[12], buffer
[13],
151 buffer
[14], buffer
[15]);
156 static int is_str_empty(const unsigned char *str
, size_t len
)
163 for (i
= 0; i
< len
; i
++)
164 if (!isspace(str
[i
]))
169 /* iso9660 [+ Microsoft Joliet Extension] */
170 int probe_iso9660(blkid_probe pr
, const struct blkid_idmag
*mag
)
172 struct iso_volume_descriptor
*iso
;
173 unsigned char label
[32];
177 if (strcmp(mag
->magic
, "CDROM") == 0)
178 return probe_iso9660_hsfs(pr
, mag
);
180 iso
= blkid_probe_get_sb(pr
, mag
, struct iso_volume_descriptor
);
182 return errno
? -errno
: 1;
184 memcpy(label
, iso
->volume_id
, sizeof(label
));
186 if (!is_str_empty(iso
->system_id
, sizeof(iso
->system_id
)))
187 blkid_probe_set_id_label(pr
, "SYSTEM_ID",
188 iso
->system_id
, sizeof(iso
->system_id
));
190 if (!is_str_empty(iso
->publisher_id
, sizeof(iso
->publisher_id
)))
191 blkid_probe_set_id_label(pr
, "PUBLISHER_ID",
192 iso
->publisher_id
, sizeof(iso
->publisher_id
));
194 if (!is_str_empty(iso
->application_id
, sizeof(iso
->application_id
)))
195 blkid_probe_set_id_label(pr
, "APPLICATION_ID",
196 iso
->application_id
, sizeof(iso
->application_id
));
198 /* create an UUID using the modified/created date */
199 if (! probe_iso9660_set_uuid(pr
, &iso
->modified
))
200 probe_iso9660_set_uuid(pr
, &iso
->created
);
202 /* Joliet Extension and Boot Record */
204 for (i
= 0; i
< ISO_VD_MAX
; i
++) {
205 struct boot_record
*boot
= (struct boot_record
*)
206 blkid_probe_get_buffer(pr
,
208 max(sizeof(struct boot_record
),
209 sizeof(struct iso_volume_descriptor
)));
211 if (boot
== NULL
|| boot
->vd_type
== ISO_VD_END
)
214 if (boot
->vd_type
== ISO_VD_BOOT_RECORD
) {
215 if (!is_str_empty(boot
->boot_system_id
,
216 sizeof(boot
->boot_system_id
)))
217 blkid_probe_set_id_label(pr
, "BOOT_SYSTEM_ID",
218 boot
->boot_system_id
,
219 sizeof(boot
->boot_system_id
));
220 off
+= ISO_SECTOR_SIZE
;
224 /* Not a Boot record, lets see if its supplementary volume descriptor */
225 iso
= (struct iso_volume_descriptor
*) boot
;
227 if (iso
->vd_type
!= ISO_VD_SUPPLEMENTARY
) {
228 off
+= ISO_SECTOR_SIZE
;
232 if (memcmp(iso
->escape_sequences
, "%/@", 3) == 0 ||
233 memcmp(iso
->escape_sequences
, "%/C", 3) == 0 ||
234 memcmp(iso
->escape_sequences
, "%/E", 3) == 0) {
236 blkid_probe_set_version(pr
, "Joliet Extension");
238 /* Is the Joliet (UTF16BE) label equal to the label in
239 * the PVD? If yes, use PVD label. The Joliet version
240 * of the label could be trimmed (because UTF16..).
242 if (ascii_eq_utf16be(label
, iso
->volume_id
, 32))
245 blkid_probe_set_utf8label(pr
,
247 sizeof(iso
->volume_id
),
251 off
+= ISO_SECTOR_SIZE
;
254 /* Joliet not found, let use standard iso label */
255 blkid_probe_set_label(pr
, label
, sizeof(label
));
261 const struct blkid_idinfo iso9660_idinfo
=
264 .usage
= BLKID_USAGE_FILESYSTEM
,
265 .probefunc
= probe_iso9660
,
266 .flags
= BLKID_IDINFO_TOLERANT
,
269 { .magic
= "CD001", .len
= 5, .kboff
= 32, .sboff
= 1 },
270 { .magic
= "CDROM", .len
= 5, .kboff
= 32, .sboff
= 9 },