chiark / gitweb /
volume_id: remove deprecated functions and bump major version
[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 it
7  *      under the terms of the GNU General Public License as published by the
8  *      Free Software Foundation version 2 of the License.
9  */
10
11 #ifndef _GNU_SOURCE
12 #define _GNU_SOURCE 1
13 #endif
14
15 #ifdef HAVE_CONFIG_H
16 #  include <config.h>
17 #endif
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <ctype.h>
25
26 #include "libvolume_id.h"
27 #include "libvolume_id-private.h"
28 #include "util.h"
29
30 struct volume_descriptor {
31         struct descriptor_tag {
32                 uint16_t        id;
33                 uint16_t        version;
34                 uint8_t         checksum;
35                 uint8_t         reserved;
36                 uint16_t        serial;
37                 uint16_t        crc;
38                 uint16_t        crc_len;
39                 uint32_t        location;
40         } PACKED tag;
41         union {
42                 struct anchor_descriptor {
43                         uint32_t        length;
44                         uint32_t        location;
45                 } PACKED anchor;
46                 struct primary_descriptor {
47                         uint32_t        seq_num;
48                         uint32_t        desc_num;
49                         struct dstring {
50                                 uint8_t clen;
51                                 uint8_t c[31];
52                         } PACKED ident;
53                 } PACKED primary;
54         } PACKED type;
55 } PACKED;
56
57 struct volume_structure_descriptor {
58         uint8_t         type;
59         uint8_t         id[5];
60         uint8_t         version;
61 } PACKED;
62
63 #define UDF_VSD_OFFSET                  0x8000
64
65 int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size)
66 {
67         struct volume_descriptor *vd;
68         struct volume_structure_descriptor *vsd;
69         unsigned int bs;
70         unsigned int b;
71         unsigned int type;
72         unsigned int count;
73         unsigned int loc;
74         unsigned int clen;
75
76         info("probing at offset 0x%llx\n", (unsigned long long) off);
77
78         vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
79         if (vsd == NULL)
80                 return -1;
81
82         if (memcmp(vsd->id, "NSR02", 5) == 0)
83                 goto blocksize;
84         if (memcmp(vsd->id, "NSR03", 5) == 0)
85                 goto blocksize;
86         if (memcmp(vsd->id, "BEA01", 5) == 0)
87                 goto blocksize;
88         if (memcmp(vsd->id, "BOOT2", 5) == 0)
89                 goto blocksize;
90         if (memcmp(vsd->id, "CD001", 5) == 0)
91                 goto blocksize;
92         if (memcmp(vsd->id, "CDW02", 5) == 0)
93                 goto blocksize;
94         if (memcmp(vsd->id, "TEA03", 5) == 0)
95                 goto blocksize;
96         return -1;
97
98 blocksize:
99         /* search the next VSD to get the logical block size of the volume */
100         for (bs = 0x800; bs < 0x8000; bs += 0x800) {
101                 vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
102                 if (vsd == NULL)
103                         return -1;
104                 dbg("test for blocksize: 0x%x\n", bs);
105                 if (vsd->id[0] != '\0')
106                         goto nsr;
107         }
108         return -1;
109
110 nsr:
111         /* search the list of VSDs for a NSR descriptor */
112         for (b = 0; b < 64; b++) {
113                 vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
114                 if (vsd == NULL)
115                         return -1;
116
117                 dbg("vsd: %c%c%c%c%c\n",
118                     vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
119
120                 if (vsd->id[0] == '\0')
121                         return -1;
122                 if (memcmp(vsd->id, "NSR02", 5) == 0)
123                         goto anchor;
124                 if (memcmp(vsd->id, "NSR03", 5) == 0)
125                         goto anchor;
126         }
127         return -1;
128
129 anchor:
130         /* read anchor volume descriptor */
131         vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + (256 * bs), 0x200);
132         if (vd == NULL)
133                 return -1;
134
135         type = le16_to_cpu(vd->tag.id);
136         if (type != 2) /* TAG_ID_AVDP */
137                 goto found;
138
139         /* get desriptor list address and block count */
140         count = le32_to_cpu(vd->type.anchor.length) / bs;
141         loc = le32_to_cpu(vd->type.anchor.location);
142         dbg("0x%x descriptors starting at logical secor 0x%x\n", count, loc);
143
144         /* pick the primary descriptor from the list */
145         for (b = 0; b < count; b++) {
146                 vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200);
147                 if (vd == NULL)
148                         return -1;
149
150                 type = le16_to_cpu(vd->tag.id);
151                 dbg("descriptor type %i\n", type);
152
153                 /* check validity */
154                 if (type == 0)
155                         goto found;
156                 if (le32_to_cpu(vd->tag.location) != loc + b)
157                         goto found;
158
159                 if (type == 1) /* TAG_ID_PVD */
160                         goto pvd;
161         }
162         goto found;
163
164 pvd:
165         volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32);
166
167         clen = vd->type.primary.ident.clen;
168         dbg("label string charsize=%i bit\n", clen);
169         if (clen == 8)
170                 volume_id_set_label_string(id, vd->type.primary.ident.c, 31);
171         else if (clen == 16)
172                 volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
173
174 found:
175         volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
176         id->type = "udf";
177
178         return 0;
179 }