2 * MS-DOS partition parsing code
4 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
9 * Inspired by fdisk, partx, Linux kernel and libparted.
16 #include "partitions.h"
19 /* see superblocks/vfat.c */
20 extern int blkid_probe_is_vfat(blkid_probe pr
);
22 static const struct dos_subtypes
{
24 const struct blkid_idinfo
*id
;
26 { MBR_FREEBSD_PARTITION
, &bsd_pt_idinfo
},
27 { MBR_NETBSD_PARTITION
, &bsd_pt_idinfo
},
28 { MBR_OPENBSD_PARTITION
, &bsd_pt_idinfo
},
29 { MBR_UNIXWARE_PARTITION
, &unixware_pt_idinfo
},
30 { MBR_SOLARIS_X86_PARTITION
, &solaris_x86_pt_idinfo
},
31 { MBR_MINIX_PARTITION
, &minix_pt_idinfo
}
34 static inline int is_extended(struct dos_partition
*p
)
36 return (p
->sys_ind
== MBR_DOS_EXTENDED_PARTITION
||
37 p
->sys_ind
== MBR_W95_EXTENDED_PARTITION
||
38 p
->sys_ind
== MBR_LINUX_EXTENDED_PARTITION
);
41 static int parse_dos_extended(blkid_probe pr
, blkid_parttable tab
,
42 uint32_t ex_start
, uint32_t ex_size
, int ssf
)
44 blkid_partlist ls
= blkid_probe_get_partlist(pr
);
45 uint32_t cur_start
= ex_start
, cur_size
= ex_size
;
47 int ct_nodata
= 0; /* count ext.partitions without data partitions */
51 struct dos_partition
*p
, *p0
;
54 if (++ct_nodata
> 100)
55 return BLKID_PROBE_OK
;
56 data
= blkid_probe_get_sector(pr
, cur_start
);
60 goto leave
; /* malformed partition? */
63 if (!mbr_is_valid_magic(data
))
66 p0
= mbr_get_partition(data
, 0);
68 /* Usually, the first entry is the real data partition,
69 * the 2nd entry is the next extended partition, or empty,
70 * and the 3rd and 4th entries are unused.
71 * However, DRDOS sometimes has the extended partition as
72 * the first entry (when the data partition is empty),
73 * and OS/2 seems to use all four entries.
74 * -- Linux kernel fs/partitions/dos.c
76 * See also http://en.wikipedia.org/wiki/Extended_boot_record
79 /* Parse data partition */
80 for (p
= p0
, i
= 0; i
< 4; i
++, p
++) {
84 /* the start is relative to the parental ext.partition */
85 start
= dos_partition_get_start(p
) * ssf
;
86 size
= dos_partition_get_size(p
) * ssf
;
87 abs_start
= cur_start
+ start
; /* absolute start */
89 if (!size
|| is_extended(p
))
92 /* extra checks to detect real data on
93 * 3rd and 4th entries */
94 if (start
+ size
> cur_size
)
96 if (abs_start
< ex_start
)
98 if (abs_start
+ size
> ex_start
+ ex_size
)
102 par
= blkid_partlist_add_partition(ls
, tab
, abs_start
, size
);
106 blkid_partition_set_type(par
, p
->sys_ind
);
107 blkid_partition_set_flags(par
, p
->boot_ind
);
108 blkid_partition_gen_uuid(par
);
111 /* The first nested ext.partition should be a link to the next
112 * logical partition. Everything other (recursive ext.partitions)
115 for (p
= p0
, i
= 0; i
< 4; i
++, p
++) {
116 start
= dos_partition_get_start(p
) * ssf
;
117 size
= dos_partition_get_size(p
) * ssf
;
119 if (size
&& is_extended(p
))
125 cur_start
= ex_start
+ start
;
129 return BLKID_PROBE_OK
;
132 static int probe_dos_pt(blkid_probe pr
,
133 const struct blkid_idmag
*mag
__attribute__((__unused__
)))
137 blkid_parttable tab
= NULL
;
139 struct dos_partition
*p0
, *p
;
141 uint32_t start
, size
, id
;
145 data
= blkid_probe_get_sector(pr
, 0);
152 /* ignore disks with AIX magic number -- for more details see aix.c */
153 if (memcmp(data
, BLKID_AIX_MAGIC_STRING
, BLKID_AIX_MAGIC_STRLEN
) == 0)
156 p0
= mbr_get_partition(data
, 0);
159 * Reject PT where boot indicator is not 0 or 0x80.
161 for (p
= p0
, i
= 0; i
< 4; i
++, p
++)
162 if (p
->boot_ind
!= 0 && p
->boot_ind
!= 0x80) {
163 DBG(LOWPROBE
, ul_debug("missing boot indicator -- ignore"));
170 for (p
= p0
, i
= 0; i
< 4; i
++, p
++) {
171 if (p
->sys_ind
== MBR_GPT_PARTITION
) {
172 DBG(LOWPROBE
, ul_debug("probably GPT -- ignore"));
178 * Now that the 55aa signature is present, this is probably
179 * either the boot sector of a FAT filesystem or a DOS-type
182 if (blkid_probe_is_vfat(pr
) == 1) {
183 DBG(LOWPROBE
, ul_debug("probably FAT -- ignore"));
187 blkid_probe_use_wiper(pr
, MBR_PT_OFFSET
, 512 - MBR_PT_OFFSET
);
189 id
= mbr_get_id(data
);
191 snprintf(idstr
, sizeof(idstr
), "%08x", id
);
194 * Well, all checks pass, it's MS-DOS partition table
196 if (blkid_partitions_need_typeonly(pr
)) {
197 /* Non-binary interface -- caller does not ask for details
198 * about partitions, just set generic variables only. */
200 blkid_partitions_strcpy_ptuuid(pr
, idstr
);
204 ls
= blkid_probe_get_partlist(pr
);
208 /* sector size factor (the start and size are in the real sectors, but
209 * we need to convert all sizes to 512 logical sectors
211 ssf
= blkid_probe_get_sectorsize(pr
) / 512;
213 /* allocate a new partition table */
214 tab
= blkid_partlist_new_parttable(ls
, "dos", MBR_PT_OFFSET
);
219 blkid_parttable_set_id(tab
, (unsigned char *) idstr
);
221 /* Parse primary partitions */
222 for (p
= p0
, i
= 0; i
< 4; i
++, p
++) {
225 start
= dos_partition_get_start(p
) * ssf
;
226 size
= dos_partition_get_size(p
) * ssf
;
229 /* Linux kernel ignores empty partitions, but partno for
230 * the empty primary partitions is not reused */
231 blkid_partlist_increment_partno(ls
);
234 par
= blkid_partlist_add_partition(ls
, tab
, start
, size
);
238 blkid_partition_set_type(par
, p
->sys_ind
);
239 blkid_partition_set_flags(par
, p
->boot_ind
);
240 blkid_partition_gen_uuid(par
);
243 /* Linux uses partition numbers greater than 4
244 * for all logical partition and all nested partition tables (bsd, ..)
246 blkid_partlist_set_partno(ls
, 5);
248 /* Parse logical partitions */
249 for (p
= p0
, i
= 0; i
< 4; i
++, p
++) {
250 start
= dos_partition_get_start(p
) * ssf
;
251 size
= dos_partition_get_size(p
) * ssf
;
255 if (is_extended(p
) &&
256 parse_dos_extended(pr
, tab
, start
, size
, ssf
) == -1)
260 /* Parse subtypes (nested partitions) on large disks */
261 if (!blkid_probe_is_tiny(pr
)) {
262 for (p
= p0
, i
= 0; i
< 4; i
++, p
++) {
266 if (!dos_partition_get_size(p
) || is_extended(p
))
269 for (n
= 0; n
< ARRAY_SIZE(dos_nested
); n
++) {
270 if (dos_nested
[n
].type
!= p
->sys_ind
)
273 rc
= blkid_partitions_do_subprobe(pr
,
274 blkid_partlist_get_partition(ls
, i
),
282 return BLKID_PROBE_OK
;
285 return BLKID_PROBE_NONE
;
289 const struct blkid_idinfo dos_pt_idinfo
=
292 .probefunc
= probe_dos_pt
,
295 /* DOS master boot sector:
298 * 440 | Optional Disk signature
299 * 446 | Partition table
303 { .magic
= "\x55\xAA", .len
= 2, .sboff
= 510 },