]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libblkid/src/superblocks/iso9660.c
libblkid: fix compiler warnings [-Wmissing-prototypes]
[thirdparty/util-linux.git] / libblkid / src / superblocks / iso9660.c
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 "iso9660.h"
23
24 struct iso9660_date {
25 unsigned char year[4];
26 unsigned char month[2];
27 unsigned char day[2];
28 unsigned char hour[2];
29 unsigned char minute[2];
30 unsigned char second[2];
31 unsigned char hundredth[2];
32 unsigned char offset;
33 } __attribute__ ((packed));
34
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;
40 unsigned char flags;
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));
54
55 /* Boot Record */
56 struct boot_record {
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));
64
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
71 #define ISO_VD_MAX 16
72
73 struct high_sierra_volume_descriptor {
74 unsigned char foo[8];
75 unsigned char type;
76 unsigned char id[5];
77 unsigned char version;
78 unsigned char unused1;
79 unsigned char system_id[32];
80 unsigned char volume_id[32];
81 } __attribute__((packed));
82
83 /* returns 1 if the begin of @ascii is equal to @utf16 string.
84 */
85 static int ascii_eq_utf16be(unsigned char *ascii,
86 unsigned char *utf16, size_t len)
87 {
88 size_t a, u;
89
90 for (a = 0, u = 0; u < len; a++, u += 2) {
91 if (utf16[u] != 0x0 || ascii[a] != utf16[u + 1])
92 return 0;
93 }
94 return 1;
95 }
96
97 /* old High Sierra format */
98 static int probe_iso9660_hsfs(blkid_probe pr, const struct blkid_idmag *mag)
99 {
100 struct high_sierra_volume_descriptor *iso;
101
102 iso = blkid_probe_get_sb(pr, mag, struct high_sierra_volume_descriptor);
103 if (!iso)
104 return errno ? -errno : 1;
105
106 blkid_probe_set_version(pr, "High Sierra");
107 blkid_probe_set_label(pr, iso->volume_id, sizeof(iso->volume_id));
108 return 0;
109 }
110
111 static int probe_iso9660_set_uuid (blkid_probe pr, const struct iso9660_date *date)
112 {
113 unsigned char buffer[16];
114 unsigned int i, zeros = 0;
115
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];
132
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')
136 zeros++;
137
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)
140 return 0;
141
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]);
152
153 return 1;
154 }
155
156 static int is_str_empty(const unsigned char *str, size_t len)
157 {
158 size_t i;
159
160 if (!str || !*str)
161 return 1;
162
163 for (i = 0; i < len; i++)
164 if (!isspace(str[i]))
165 return 0;
166 return 1;
167 }
168
169 /* iso9660 [+ Microsoft Joliet Extension] */
170 int probe_iso9660(blkid_probe pr, const struct blkid_idmag *mag)
171 {
172 struct iso_volume_descriptor *iso;
173 unsigned char label[32];
174 int i;
175 int off;
176
177 if (strcmp(mag->magic, "CDROM") == 0)
178 return probe_iso9660_hsfs(pr, mag);
179
180 iso = blkid_probe_get_sb(pr, mag, struct iso_volume_descriptor);
181 if (!iso)
182 return errno ? -errno : 1;
183
184 memcpy(label, iso->volume_id, sizeof(label));
185
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));
189
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));
193
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));
197
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);
201
202 /* Joliet Extension and Boot Record */
203 off = ISO_VD_OFFSET;
204 for (i = 0; i < ISO_VD_MAX; i++) {
205 struct boot_record *boot= (struct boot_record *)
206 blkid_probe_get_buffer(pr,
207 off,
208 max(sizeof(struct boot_record),
209 sizeof(struct iso_volume_descriptor)));
210
211 if (boot == NULL || boot->vd_type == ISO_VD_END)
212 break;
213
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;
221 continue;
222 }
223
224 /* Not a Boot record, lets see if its supplemntary volume descriptor */
225 iso = (struct iso_volume_descriptor *) boot;
226
227 if (iso->vd_type != ISO_VD_SUPPLEMENTARY) {
228 off += ISO_SECTOR_SIZE;
229 continue;
230 }
231
232 if (memcmp(iso->escape_sequences, "%/@", 3) == 0 ||
233 memcmp(iso->escape_sequences, "%/C", 3) == 0 ||
234 memcmp(iso->escape_sequences, "%/E", 3) == 0) {
235
236 blkid_probe_set_version(pr, "Joliet Extension");
237
238 /* Is the Joliet (UTF16BE) label equal to the label in
239 * the PVD? If yes, use PVD label. The Jolied version
240 * of the label could be trimed (because UTF16..).
241 */
242 if (ascii_eq_utf16be(label, iso->volume_id, 32))
243 break;
244
245 blkid_probe_set_utf8label(pr,
246 iso->volume_id,
247 sizeof(iso->volume_id),
248 BLKID_ENC_UTF16BE);
249 goto has_label;
250 }
251 off += ISO_SECTOR_SIZE;
252 }
253
254 /* Joliet not found, let use standard iso label */
255 blkid_probe_set_label(pr, label, sizeof(label));
256
257 has_label:
258 return 0;
259 }
260
261 const struct blkid_idinfo iso9660_idinfo =
262 {
263 .name = "iso9660",
264 .usage = BLKID_USAGE_FILESYSTEM,
265 .probefunc = probe_iso9660,
266 .flags = BLKID_IDINFO_TOLERANT,
267 .magics =
268 {
269 { .magic = "CD001", .len = 5, .kboff = 32, .sboff = 1 },
270 { .magic = "CDROM", .len = 5, .kboff = 32, .sboff = 9 },
271 { NULL }
272 }
273 };
274