bc: convert to "G trick" - this returns bc to zero bss increase
[oweals/busybox.git] / util-linux / volume_id / 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 library is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU Lesser General Public
8  *      License as published by the Free Software Foundation; either
9  *      version 2.1 of the License, or (at your option) any later version.
10  *
11  *      This library 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 GNU
14  *      Lesser General Public License for more details.
15  *
16  *      You should have received a copy of the GNU Lesser General Public
17  *      License along with this library; if not, write to the Free Software
18  *      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 //config:config FEATURE_VOLUMEID_UDF
21 //config:       bool "udf filesystem"
22 //config:       default y
23 //config:       depends on VOLUMEID
24
25 //kbuild:lib-$(CONFIG_FEATURE_VOLUMEID_UDF) += udf.o
26
27 #include "volume_id_internal.h"
28
29 struct volume_descriptor {
30         struct descriptor_tag {
31                 uint16_t        id;
32                 uint16_t        version;
33                 uint8_t         checksum;
34                 uint8_t         reserved;
35                 uint16_t        serial;
36                 uint16_t        crc;
37                 uint16_t        crc_len;
38                 uint32_t        location;
39         } PACKED tag;
40         union {
41                 struct anchor_descriptor {
42                         uint32_t        length;
43                         uint32_t        location;
44                 } PACKED anchor;
45                 struct primary_descriptor {
46                         uint32_t        seq_num;
47                         uint32_t        desc_num;
48                         struct dstring {
49                                 uint8_t clen;
50                                 uint8_t c[31];
51                         } PACKED ident;
52                 } PACKED primary;
53         } PACKED type;
54 } PACKED;
55
56 struct volume_structure_descriptor {
57         uint8_t         type;
58         uint8_t         id[5];
59         uint8_t         version;
60 } PACKED;
61
62 #define UDF_VSD_OFFSET                  0x8000
63
64 int FAST_FUNC volume_id_probe_udf(struct volume_id *id /*,uint64_t off*/)
65 {
66 #define off ((uint64_t)0)
67         struct volume_descriptor *vd;
68         struct volume_structure_descriptor *vsd;
69         unsigned bs;
70         unsigned b;
71         unsigned type;
72         unsigned count;
73         unsigned loc;
74         unsigned clen;
75
76         dbg("probing at offset 0x%llx", (unsigned long long) off);
77
78         vsd = 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 = 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", 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 = 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",
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 = 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 descriptor 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", count, loc);
143
144         /* pick the primary descriptor from the list */
145         for (b = 0; b < count; b++) {
146                 vd = 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", 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", 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         IF_FEATURE_BLKID_TYPE(id->type = "udf";)
177         return 0;
178 }