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

« back to all changes in this revision

Viewing changes to libblkid/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,
 
132
                const struct blkid_idmag *mag __attribute__((__unused__)))
 
133
{
 
134
        int i;
 
135
        int ssf;
 
136
        blkid_parttable tab = NULL;
 
137
        blkid_partlist ls;
 
138
        struct dos_partition *p0, *p;
 
139
        unsigned char *data;
 
140
        uint32_t start, size;
 
141
 
 
142
        data = blkid_probe_get_sector(pr, 0);
 
143
        if (!data)
 
144
                goto nothing;
 
145
 
 
146
        /* ignore disks with AIX magic number -- for more details see aix.c */
 
147
        if (memcmp(data, BLKID_AIX_MAGIC_STRING, BLKID_AIX_MAGIC_STRLEN) == 0)
 
148
                goto nothing;
 
149
 
 
150
        /*
 
151
         * Now that the 55aa signature is present, this is probably
 
152
         * either the boot sector of a FAT filesystem or a DOS-type
 
153
         * partition table.
 
154
         */
 
155
        if (blkid_probe_is_vfat(pr)) {
 
156
                DBG(DEBUG_LOWPROBE, printf("probably FAT -- ignore\n"));
 
157
                goto nothing;
 
158
        }
 
159
 
 
160
        p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);
 
161
 
 
162
        /*
 
163
         * Reject PT where boot indicator is not 0 or 0x80.
 
164
         */
 
165
        for (p = p0, i = 0; i < 4; i++, p++)
 
166
                if (p->boot_ind != 0 && p->boot_ind != 0x80) {
 
167
                        DBG(DEBUG_LOWPROBE, printf("missing boot indicator -- ignore\n"));
 
168
                        goto nothing;
 
169
                }
 
170
 
 
171
        /*
 
172
         * GPT uses valid MBR
 
173
         */
 
174
        for (p = p0, i = 0; i < 4; i++, p++) {
 
175
                if (p->sys_type == BLKID_GPT_PARTITION) {
 
176
                        DBG(DEBUG_LOWPROBE, printf("probably GPT -- ignore\n"));
 
177
                        goto nothing;
 
178
                }
 
179
        }
 
180
 
 
181
        blkid_probe_use_wiper(pr, BLKID_MSDOS_PT_OFFSET,
 
182
                                  512 - BLKID_MSDOS_PT_OFFSET);
 
183
 
 
184
        /*
 
185
         * Well, all checks pass, it's MS-DOS partiton table
 
186
         */
 
187
        if (blkid_partitions_need_typeonly(pr))
 
188
                /* caller does not ask for details about partitions */
 
189
                return 0;
 
190
 
 
191
        ls = blkid_probe_get_partlist(pr);
 
192
 
 
193
        /* sector size factor (the start and size are in the real sectors, but
 
194
         * we need to convert all sizes to 512 logical sectors
 
195
         */
 
196
        ssf = blkid_probe_get_sectorsize(pr) / 512;
 
197
 
 
198
        /* allocate a new partition table */
 
199
        tab = blkid_partlist_new_parttable(ls, "dos", BLKID_MSDOS_PT_OFFSET);
 
200
        if (!tab)
 
201
                goto err;
 
202
 
 
203
        /* Parse primary partitions */
 
204
        for (p = p0, i = 0; i < 4; i++, p++) {
 
205
                blkid_partition par;
 
206
 
 
207
                start = dos_partition_start(p) * ssf;
 
208
                size = dos_partition_size(p) * ssf;
 
209
 
 
210
                if (!size) {
 
211
                        /* Linux kernel ignores empty partitions, but partno for
 
212
                         * the empty primary partitions is not reused */
 
213
                        blkid_partlist_increment_partno(ls);
 
214
                        continue;
 
215
                }
 
216
                par = blkid_partlist_add_partition(ls, tab, start, size);
 
217
                if (!par)
 
218
                        goto err;
 
219
 
 
220
                blkid_partition_set_type(par, p->sys_type);
 
221
                blkid_partition_set_flags(par, p->boot_ind);
 
222
        }
 
223
 
 
224
        /* Linux uses partition numbers greater than 4
 
225
         * for all logical partition and all nested partition tables (bsd, ..)
 
226
         */
 
227
        blkid_partlist_set_partno(ls, 5);
 
228
 
 
229
        /* Parse logical partitions */
 
230
        for (p = p0, i = 0; i < 4; i++, p++) {
 
231
                start = dos_partition_start(p) * ssf;
 
232
                size = dos_partition_size(p) * ssf;
 
233
 
 
234
                if (!size)
 
235
                        continue;
 
236
                if (is_extended(p) &&
 
237
                    parse_dos_extended(pr, tab, start, size, ssf) == -1)
 
238
                        goto err;
 
239
        }
 
240
 
 
241
        /* Parse subtypes (nested partitions) on large disks */
 
242
        if (!blkid_probe_is_tiny(pr)) {
 
243
                for (p = p0, i = 0; i < 4; i++, p++) {
 
244
                        size_t n;
 
245
 
 
246
                        if (!dos_partition_size(p) || is_extended(p))
 
247
                                continue;
 
248
 
 
249
                        for (n = 0; n < ARRAY_SIZE(dos_nested); n++) {
 
250
                                if (dos_nested[n].type != p->sys_type)
 
251
                                        continue;
 
252
 
 
253
                                if (blkid_partitions_do_subprobe(pr,
 
254
                                                blkid_partlist_get_partition(ls, i),
 
255
                                                dos_nested[n].id) == -1)
 
256
                                        goto err;
 
257
                                break;
 
258
                        }
 
259
                }
 
260
        }
 
261
        return 0;
 
262
 
 
263
nothing:
 
264
        return 1;
 
265
err:
 
266
        return -1;
 
267
}
 
268
 
 
269
 
 
270
const struct blkid_idinfo dos_pt_idinfo =
 
271
{
 
272
        .name           = "dos",
 
273
        .probefunc      = probe_dos_pt,
 
274
        .magics         =
 
275
        {
 
276
                /* DOS master boot sector:
 
277
                 *
 
278
                 *     0 | Code Area
 
279
                 *   440 | Optional Disk signature
 
280
                 *   446 | Partition table
 
281
                 *   510 | 0x55
 
282
                 *   511 | 0xAA
 
283
                 */
 
284
                { .magic = "\x55\xAA", .len = 2, .sboff = 510 },
 
285
                { NULL }
 
286
        }
 
287
};
 
288