Adding upstream version 4.00~pre61+dfsg.
[syslinux-debian/hramrach.git] / com32 / gpllib / disk / msdos.c
blobaffec43b46c538db6922287788fac44cfeab83f5
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2009 Pierre-Alexandre Meyer
5 * Some parts borrowed from chain.c32:
7 * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
8 * Copyright 2009 Intel Corporation; author: H. Peter Anvin
10 * This file is part of Syslinux, and is made available under
11 * the terms of the GNU General Public License version 2.
13 * ----------------------------------------------------------------------- */
15 #include <stdlib.h>
17 #include <disk/common.h>
18 #include <disk/geom.h>
19 #include <disk/msdos.h>
20 #include <disk/partition.h>
21 #include <disk/read.h>
23 static inline int is_extended_partition(struct part_entry *ptab)
25 return (ptab->ostype == 0x05 ||
26 ptab->ostype == 0x0f || ptab->ostype == 0x85);
29 static inline int msdos_magic_present(const char *ptab)
31 return (*(uint16_t *) (ptab + 0x1fe) == 0xaa55);
34 /**
35 * process_extended_partition - execute a callback for each partition contained listed in an ebr
36 * @drive_info: driveinfo struct describing the drive
37 * @partition_offset: Absolute start (lba) of the extended partition
38 * @ebr_offset: Relative start (lba) of the current ebr processed within
39 * the extended partition
40 * @callback: Callback to execute
41 * @error: Buffer for I/O errors
42 * @nb_part_seen: Number of partitions found on the disk so far
43 **/
44 static int process_extended_partition(struct driveinfo *drive_info,
45 const int partition_offset,
46 const int ebr_offset,
47 p_callback callback, int nb_part_seen)
49 int status = 0;
50 /* The ebr is located at the first sector of the extended partition */
51 char *ebr = malloc(SECTOR * sizeof(char));
53 if (read_sectors(drive_info, ebr, partition_offset + ebr_offset, 1) == -1)
54 goto abort;
56 /* Check msdos magic signature */
57 if (!msdos_magic_present(ebr))
58 goto abort;
60 struct part_entry *ptab =
61 (struct part_entry *)(ebr + PARTITION_TABLES_OFFSET);
63 for (int i = 0; i < 4; i++) {
64 if (status == -1)
65 goto abort;
67 if (!is_extended_partition(&ptab[i])) {
69 * This EBR partition table entry points to the
70 * logical partition associated to that EBR
72 int logical_partition_start = ebr_offset + ptab[i].start_lba;
74 /* Last EBR in the extended partition? */
75 if (!logical_partition_start)
76 continue;
79 * Check for garbage:
80 * 3rd and 4th entries in an EBR should be zero
81 * Some (malformed) partitioning software still add some
82 * data partitions there.
84 if (ptab[i].start_lba <= 0 || ptab[i].length <= 0)
85 continue;
87 nb_part_seen++;
88 callback(drive_info,
89 &ptab[i],
90 partition_offset + logical_partition_start, nb_part_seen);
91 } else
92 status = process_extended_partition(drive_info,
93 partition_offset,
94 ptab[i].start_lba,
95 callback, nb_part_seen);
98 free(ebr);
99 return 0;
101 abort:
102 free(ebr);
103 return -1;
107 * process_mbr - execute a callback for each partition contained in an {m,e}br
108 * @drive_info: driveinfo struct describing the drive
109 * @ptab: Pointer to the partition table
110 * @callback: Callback to execute
112 static int process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
113 p_callback callback)
115 int status = 0;
117 for (int i = 0; i < 4; i++) {
118 if (status == -1)
119 return -1;
121 if (ptab[i].start_sect > 0) {
122 if (is_extended_partition(&ptab[i])) {
123 callback(drive_info, &ptab[i], ptab[i].start_lba, i + 1);
124 status =
125 process_extended_partition(drive_info, ptab[i].start_lba, 0,
126 callback, 4);
127 } else
128 callback(drive_info, &ptab[i], ptab[i].start_lba, i + 1);
132 return 0;
136 * parse_partition_table - execute a callback for each partition entry
137 * @d: driveinfo struct describing the drive
138 * @callback: Callback to execute
140 * The signature of the callback should be the following:
142 * void callback(struct driveinfo *drive_info,
143 * struct part_entry *ptab,
144 * int offset_root,
145 * int nb_part_seen)
147 int parse_partition_table(struct driveinfo *d, p_callback callback)
149 char *mbr = malloc(SECTOR * sizeof(char));
151 if (read_mbr(d->disk, mbr) == -1)
152 return -1;
153 else {
154 /* Check msdos magic signature */
155 if (!msdos_magic_present(mbr))
156 return -1;
158 struct part_entry *ptab =
159 (struct part_entry *)(mbr + PARTITION_TABLES_OFFSET);
160 return process_mbr(d, ptab, callback);