~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to shlibs/blkid/src/partitions/dos.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * MS-DOS partition parsing code
3
 
 *
4
 
 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
5
 
 *
6
 
 * This file may be redistributed under the terms of the
7
 
 * GNU Lesser General Public License.
8
 
 *
9
 
 * Inspired by fdisk, partx, Linux kernel and libparted.
10
 
 */
11
 
#include <stdio.h>
12
 
#include <string.h>
13
 
#include <stdlib.h>
14
 
#include <stdint.h>
15
 
 
16
 
#include "partitions.h"
17
 
#include "dos.h"
18
 
#include "aix.h"
19
 
 
20
 
/* see superblocks/vfat.c */
21
 
extern int blkid_probe_is_vfat(blkid_probe pr);
22
 
 
23
 
static const struct dos_subtypes {
24
 
        unsigned char type;
25
 
        const struct blkid_idinfo *id;
26
 
} dos_nested[] = {
27
 
        { BLKID_FREEBSD_PARTITION, &bsd_pt_idinfo },
28
 
        { BLKID_NETBSD_PARTITION, &bsd_pt_idinfo },
29
 
        { BLKID_OPENBSD_PARTITION, &bsd_pt_idinfo },
30
 
        { BLKID_UNIXWARE_PARTITION, &unixware_pt_idinfo },
31
 
        { BLKID_SOLARIS_X86_PARTITION, &solaris_x86_pt_idinfo },
32
 
        { BLKID_MINIX_PARTITION, &minix_pt_idinfo }
33
 
};
34
 
 
35
 
static inline int is_extended(struct dos_partition *p)
36
 
{
37
 
        return (p->sys_type == BLKID_DOS_EXTENDED_PARTITION ||
38
 
                p->sys_type == BLKID_W95_EXTENDED_PARTITION ||
39
 
                p->sys_type == BLKID_LINUX_EXTENDED_PARTITION);
40
 
}
41
 
 
42
 
static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
43
 
                uint32_t ex_start, uint32_t ex_size, int ssf)
44
 
{
45
 
        blkid_partlist ls = blkid_probe_get_partlist(pr);
46
 
        uint32_t cur_start = ex_start, cur_size = ex_size;
47
 
        unsigned char *data;
48
 
        int ct_nodata = 0;      /* count ext.partitions without data partitions */
49
 
        int i;
50
 
 
51
 
        while (1) {
52
 
                struct dos_partition *p, *p0;
53
 
                uint32_t start, size;
54
 
 
55
 
                if (++ct_nodata > 100)
56
 
                        return 0;
57
 
                data = blkid_probe_get_sector(pr, cur_start);
58
 
                if (!data)
59
 
                        goto leave;     /* malformed partition? */
60
 
 
61
 
                if (!is_valid_mbr_signature(data))
62
 
                        goto leave;
63
 
 
64
 
                p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);
65
 
 
66
 
                /* Usually, the first entry is the real data partition,
67
 
                 * the 2nd entry is the next extended partition, or empty,
68
 
                 * and the 3rd and 4th entries are unused.
69
 
                 * However, DRDOS sometimes has the extended partition as
70
 
                 * the first entry (when the data partition is empty),
71
 
                 * and OS/2 seems to use all four entries.
72
 
                 * -- Linux kernel fs/partitions/dos.c
73
 
                 *
74
 
                 * See also http://en.wikipedia.org/wiki/Extended_boot_record
75
 
                 */
76
 
 
77
 
                /* Parse data partition */
78
 
                for (p = p0, i = 0; i < 4; i++, p++) {
79
 
                        uint32_t abs_start;
80
 
                        blkid_partition par;
81
 
 
82
 
                        /* the start is relative to the parental ext.partition */
83
 
                        start = dos_partition_start(p) * ssf;
84
 
                        size = dos_partition_size(p) * ssf;
85
 
                        abs_start = cur_start + start;  /* absolute start */
86
 
 
87
 
                        if (!size || is_extended(p))
88
 
                                continue;
89
 
                        if (i >= 2) {
90
 
                                /* extra checks to detect real data on
91
 
                                 * 3rd and 4th entries */
92
 
                                if (start + size > cur_size)
93
 
                                        continue;
94
 
                                if (abs_start < ex_start)
95
 
                                        continue;
96
 
                                if (abs_start + size > ex_start + ex_size)
97
 
                                        continue;
98
 
                        }
99
 
 
100
 
                        par = blkid_partlist_add_partition(ls, tab, abs_start, size);
101
 
                        if (!par)
102
 
                                goto err;
103
 
 
104
 
                        blkid_partition_set_type(par, p->sys_type);
105
 
                        blkid_partition_set_flags(par, p->boot_ind);
106
 
                        ct_nodata = 0;
107
 
                }
108
 
                /* The first nested ext.partition should be a link to the next
109
 
                 * logical partition. Everything other (recursive ext.partitions)
110
 
                 * is junk.
111
 
                 */
112
 
                for (p = p0, i = 0; i < 4; i++, p++) {
113
 
                        start = dos_partition_start(p) * ssf;
114
 
                        size = dos_partition_size(p) * ssf;
115
 
 
116
 
                        if (size && is_extended(p))
117
 
                                break;
118
 
                }
119
 
                if (i == 4)
120
 
                        goto leave;
121
 
 
122
 
                cur_start = ex_start + start;
123
 
                cur_size = size;
124
 
        }
125
 
leave:
126
 
        return 0;
127
 
err:
128
 
        return -1;
129
 
}
130
 
 
131
 
static int probe_dos_pt(blkid_probe pr, const struct blkid_idmag *mag)
132
 
{
133
 
        int i;
134
 
        int ssf;
135
 
        blkid_parttable tab = NULL;
136
 
        blkid_partlist ls;
137
 
        struct dos_partition *p0, *p;
138
 
        unsigned char *data;
139
 
        uint32_t start, size;
140
 
 
141
 
        data = blkid_probe_get_sector(pr, 0);
142
 
        if (!data)
143
 
                goto nothing;
144
 
 
145
 
        /* ignore disks with AIX magic number -- for more details see aix.c */
146
 
        if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0)
147
 
                goto nothing;
148
 
 
149
 
        /*
150
 
         * Now that the 55aa signature is present, this is probably
151
 
         * either the boot sector of a FAT filesystem or a DOS-type
152
 
         * partition table.
153
 
         */
154
 
        if (blkid_probe_is_vfat(pr)) {
155
 
                DBG(DEBUG_LOWPROBE, printf("probably FAT -- ignore\n"));
156
 
                goto nothing;
157
 
        }
158
 
 
159
 
        p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);
160
 
 
161
 
        /*
162
 
         * Reject PT where boot indicator is not 0 or 0x80.
163
 
         */
164
 
        for (p = p0, i = 0; i < 4; i++, p++)
165
 
                if (p->boot_ind != 0 && p->boot_ind != 0x80) {
166
 
                        DBG(DEBUG_LOWPROBE, printf("missing boot indicator -- ignore\n"));
167
 
                        goto nothing;
168
 
                }
169
 
 
170
 
        /*
171
 
         * GPT uses valid MBR
172
 
         */
173
 
        for (p = p0, i = 0; i < 4; i++, p++) {
174
 
                if (p->sys_type == BLKID_GPT_PARTITION) {
175
 
                        DBG(DEBUG_LOWPROBE, printf("probably GPT -- ignore\n"));
176
 
                        goto nothing;
177
 
                }
178
 
        }
179
 
 
180
 
        blkid_probe_use_wiper(pr, BLKID_MSDOS_PT_OFFSET,
181
 
                                  512 - BLKID_MSDOS_PT_OFFSET);
182
 
 
183
 
        /*
184
 
         * Well, all checks pass, it's MS-DOS partiton table
185
 
         */
186
 
        if (blkid_partitions_need_typeonly(pr))
187
 
                /* caller does not ask for details about partitions */
188
 
                return 0;
189
 
 
190
 
        ls = blkid_probe_get_partlist(pr);
191
 
 
192
 
        /* sector size factor (the start and size are in the real sectors, but
193
 
         * we need to convert all sizes to 512 logical sectors
194
 
         */
195
 
        ssf = blkid_probe_get_sectorsize(pr) / 512;
196
 
 
197
 
        /* allocate a new partition table */
198
 
        tab = blkid_partlist_new_parttable(ls, "dos", BLKID_MSDOS_PT_OFFSET);
199
 
        if (!tab)
200
 
                goto err;
201
 
 
202
 
        /* Parse primary partitions */
203
 
        for (p = p0, i = 0; i < 4; i++, p++) {
204
 
                blkid_partition par;
205
 
 
206
 
                start = dos_partition_start(p) * ssf;
207
 
                size = dos_partition_size(p) * ssf;
208
 
 
209
 
                if (!size) {
210
 
                        /* Linux kernel ignores empty partitions, but partno for
211
 
                         * the empty primary partitions is not reused */
212
 
                        blkid_partlist_increment_partno(ls);
213
 
                        continue;
214
 
                }
215
 
                par = blkid_partlist_add_partition(ls, tab, start, size);
216
 
                if (!par)
217
 
                        goto err;
218
 
 
219
 
                blkid_partition_set_type(par, p->sys_type);
220
 
                blkid_partition_set_flags(par, p->boot_ind);
221
 
        }
222
 
 
223
 
        /* Linux uses partition numbers greater than 4
224
 
         * for all logical partition and all nested partition tables (bsd, ..)
225
 
         */
226
 
        blkid_partlist_set_partno(ls, 5);
227
 
 
228
 
        /* Parse logical partitions */
229
 
        for (p = p0, i = 0; i < 4; i++, p++) {
230
 
                start = dos_partition_start(p) * ssf;
231
 
                size = dos_partition_size(p) * ssf;
232
 
 
233
 
                if (!size)
234
 
                        continue;
235
 
                if (is_extended(p) &&
236
 
                    parse_dos_extended(pr, tab, start, size, ssf) == -1)
237
 
                        goto err;
238
 
        }
239
 
 
240
 
        /* Parse subtypes (nested partitions) on large disks */
241
 
        if (!blkid_probe_is_tiny(pr)) {
242
 
                for (p = p0, i = 0; i < 4; i++, p++) {
243
 
                        int n;
244
 
 
245
 
                        if (!dos_partition_size(p) || is_extended(p))
246
 
                                continue;
247
 
 
248
 
                        for (n = 0; n < ARRAY_SIZE(dos_nested); n++) {
249
 
                                if (dos_nested[n].type != p->sys_type)
250
 
                                        continue;
251
 
 
252
 
                                if (blkid_partitions_do_subprobe(pr,
253
 
                                                blkid_partlist_get_partition(ls, i),
254
 
                                                dos_nested[n].id) == -1)
255
 
                                        goto err;
256
 
                                break;
257
 
                        }
258
 
                }
259
 
        }
260
 
        return 0;
261
 
 
262
 
nothing:
263
 
        return 1;
264
 
err:
265
 
        return -1;
266
 
}
267
 
 
268
 
 
269
 
const struct blkid_idinfo dos_pt_idinfo =
270
 
{
271
 
        .name           = "dos",
272
 
        .probefunc      = probe_dos_pt,
273
 
        .magics         =
274
 
        {
275
 
                /* DOS master boot sector:
276
 
                 *
277
 
                 *     0 | Code Area
278
 
                 *   440 | Optional Disk signature
279
 
                 *   446 | Partition table
280
 
                 *   510 | 0x55
281
 
                 *   511 | 0xAA
282
 
                 */
283
 
                { .magic = "\x55\xAA", .len = 2, .sboff = 510 },
284
 
                { NULL }
285
 
        }
286
 
};
287