chiark / gitweb /
udevadm: test - remove --force option
[elogind.git] / extras / volume_id / lib / udf.c
1 /*
2  * volume_id - reads filesystem label and uuid
3  *
4  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifndef _GNU_SOURCE
21 #define _GNU_SOURCE 1
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <ctype.h>
30
31 #include "libvolume_id.h"
32 #include "libvolume_id-private.h"
33
34 struct volume_descriptor {
35         struct descriptor_tag {
36                 uint16_t        id;
37                 uint16_t        version;
38                 uint8_t         checksum;
39                 uint8_t         reserved;
40                 uint16_t        serial;
41                 uint16_t        crc;
42                 uint16_t        crc_len;
43                 uint32_t        location;
44         } PACKED tag;
45         union {
46                 struct anchor_descriptor {
47                         uint32_t        length;
48                         uint32_t        location;
49                 } PACKED anchor;
50                 struct primary_descriptor {
51                         uint32_t        seq_num;
52                         uint32_t        desc_num;
53                         struct dstring {
54                                 uint8_t clen;
55                                 uint8_t c[31];
56                         } PACKED ident;
57                 } PACKED primary;
58         } PACKED type;
59 } PACKED;
60
61 struct volume_structure_descriptor {
62         uint8_t         type;
63         uint8_t         id[5];
64         uint8_t         version;
65 } PACKED;
66
67 #define UDF_VSD_OFFSET                  0x8000
68
69 int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size)
70 {
71         struct volume_descriptor *vd;
72         struct volume_structure_descriptor *vsd;
73         unsigned int bs;
74         unsigned int b;
75         unsigned int type;
76         unsigned int count;
77         unsigned int loc;
78         unsigned int clen;
79
80         info("probing at offset 0x%" PRIx64 "\n", off);
81
82         vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
83         if (vsd == NULL)
84                 return -1;
85
86         if (memcmp(vsd->id, "NSR02", 5) == 0)
87                 goto blocksize;
88         if (memcmp(vsd->id, "NSR03", 5) == 0)
89                 goto blocksize;
90         if (memcmp(vsd->id, "BEA01", 5) == 0)
91                 goto blocksize;
92         if (memcmp(vsd->id, "BOOT2", 5) == 0)
93                 goto blocksize;
94         if (memcmp(vsd->id, "CD001", 5) == 0)
95                 goto blocksize;
96         if (memcmp(vsd->id, "CDW02", 5) == 0)
97                 goto blocksize;
98         if (memcmp(vsd->id, "TEA03", 5) == 0)
99                 goto blocksize;
100         return -1;
101
102 blocksize:
103         /* search the next VSD to get the logical block size of the volume */
104         for (bs = 0x800; bs < 0x8000; bs += 0x800) {
105                 vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
106                 if (vsd == NULL)
107                         return -1;
108                 dbg("test for blocksize: 0x%x\n", bs);
109                 if (vsd->id[0] != '\0')
110                         goto nsr;
111         }
112         return -1;
113
114 nsr:
115         /* search the list of VSDs for a NSR descriptor */
116         for (b = 0; b < 64; b++) {
117                 vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
118                 if (vsd == NULL)
119                         return -1;
120
121                 dbg("vsd: %c%c%c%c%c\n",
122                     vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
123
124                 if (vsd->id[0] == '\0')
125                         return -1;
126                 if (memcmp(vsd->id, "NSR02", 5) == 0)
127                         goto anchor;
128                 if (memcmp(vsd->id, "NSR03", 5) == 0)
129                         goto anchor;
130         }
131         return -1;
132
133 anchor:
134         /* read anchor volume descriptor */
135         vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + (256 * bs), 0x200);
136         if (vd == NULL)
137                 return -1;
138
139         type = le16_to_cpu(vd->tag.id);
140         if (type != 2) /* TAG_ID_AVDP */
141                 goto found;
142
143         /* get desriptor list address and block count */
144         count = le32_to_cpu(vd->type.anchor.length) / bs;
145         loc = le32_to_cpu(vd->type.anchor.location);
146         dbg("0x%x descriptors starting at logical secor 0x%x\n", count, loc);
147
148         /* pick the primary descriptor from the list */
149         for (b = 0; b < count; b++) {
150                 vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200);
151                 if (vd == NULL)
152                         return -1;
153
154                 type = le16_to_cpu(vd->tag.id);
155                 dbg("descriptor type %i\n", type);
156
157                 /* check validity */
158                 if (type == 0)
159                         goto found;
160                 if (le32_to_cpu(vd->tag.location) != loc + b)
161                         goto found;
162
163                 if (type == 1) /* TAG_ID_PVD */
164                         goto pvd;
165         }
166         goto found;
167
168 pvd:
169         volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32);
170
171         clen = vd->type.primary.ident.clen;
172         dbg("label string charsize=%i bit\n", clen);
173         if (clen == 8)
174                 volume_id_set_label_string(id, vd->type.primary.ident.c, 31);
175         else if (clen == 16)
176                 volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
177
178 found:
179         volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
180         id->type = "udf";
181
182         return 0;
183 }