summaryrefslogtreecommitdiff
path: root/com32
diff options
context:
space:
mode:
authorPierre-Alexandre Meyer <pierre@mouraf.org>2009-04-26 14:09:18 -0700
committerPierre-Alexandre Meyer <pierre@mouraf.org>2009-04-26 14:09:18 -0700
commit262e71498984cd2518cde54961f92c12e2f5ad0a (patch)
treec34bdf48009a2c6eef926d1de8a8e60c6f6a6a3d /com32
parent3ea01d1af4dd0c22b292ce887141a95c9d629f19 (diff)
downloadsyslinux-262e71498984cd2518cde54961f92c12e2f5ad0a.tar.gz
gpllib: Add parse_partition_table() to iterate through all partitions on a disk
Impact: expand gpllib disk API parse_partition_table() can be used to execute a callback on each partition. The signature of the callback is: void callback(struct driveinfo *drive_info, struct part_entry *ptab, struct part_entry *ptab_root, int offset_root, int local_partition_number, int ebr_seen) * drive_info represents the disk. * ptab is the current partition entry processed. * ptab_root is the partition entry linking to the current one processed (extended only). * offset_root is the offset of the ebr when iterating through extended partitions (0 otherwise). * local_partition_number is the number of the partition processed (0->3). * ebr_seen counts the total number of ebr processed. Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
Diffstat (limited to 'com32')
-rw-r--r--com32/gplinclude/disk/msdos.h8
-rw-r--r--com32/gpllib/Makefile2
-rw-r--r--com32/gpllib/disk/msdos.c149
3 files changed, 158 insertions, 1 deletions
diff --git a/com32/gplinclude/disk/msdos.h b/com32/gplinclude/disk/msdos.h
new file mode 100644
index 00000000..b6dd9481
--- /dev/null
+++ b/com32/gplinclude/disk/msdos.h
@@ -0,0 +1,8 @@
+#ifndef _MSDOS_H_
+#define _MSDOS_H_
+
+#include <disk/geom.h>
+
+int parse_partition_table(struct driveinfo *, void *, int *);
+
+#endif /* _MSDOS_H_ */
diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile
index 7897af58..83f1407a 100644
--- a/com32/gpllib/Makefile
+++ b/com32/gpllib/Makefile
@@ -10,7 +10,7 @@ REQFLAGS += -I../gplinclude
LIBOBJS = dmi/dmi_battery.o dmi/dmi_chassis.o dmi/dmi_memory.o \
dmi/dmi_processor.o dmi/dmi.o dmi/dmi_bios.o dmi/dmi_base_board.o \
- dmi/dmi_ipmi.o cpuid.o disk/geom.o disk/read.o disk/write.o \
+ dmi/dmi_ipmi.o cpuid.o disk/geom.o disk/read.o disk/write.o disk/msdos.o \
disk/util.o disk/labels.o disk/swsusp.o disk/error.o vpd/vpd.o
BINDIR = /usr/bin
diff --git a/com32/gpllib/disk/msdos.c b/com32/gpllib/disk/msdos.c
new file mode 100644
index 00000000..da28b8bb
--- /dev/null
+++ b/com32/gpllib/disk/msdos.c
@@ -0,0 +1,149 @@
+#include <stdlib.h>
+#include <disk/geom.h>
+#include <disk/partition.h>
+#include <disk/read.h>
+
+static inline int is_extended_partition(struct part_entry *ptab)
+{
+ return (ptab->ostype == 0x05 ||
+ ptab->ostype == 0x0f ||
+ ptab->ostype == 0x85);
+}
+static inline int msdos_magic_present(char *ptab)
+{
+ return ( *(uint16_t *)(ptab + 0x1fe) == 0xaa55 );
+}
+
+/**
+ * process_ebr - execute a callback for each partition contained in an ebr
+ * @drive_info: driveinfo struct describing the drive
+ * @ptab_root: part_entry struct describing the root partition (pointing to the ebr)
+ * @ebr_seen: Number of ebr processed
+ * @callback: Callback to execute
+ **/
+static void process_ebr(struct driveinfo *drive_info, struct part_entry *ptab_root,
+ int ebr_seen,
+ void *callback(struct driveinfo *, struct part_entry *, struct part_entry *, int, int, int),
+ int *error, int offset_root)
+{
+ /* The ebr is located at the first sector of the extended partition */
+ char* ebr = read_sectors(drive_info, ptab_root->start_lba+offset_root, 1, error);
+ if (!ebr)
+ return;
+
+ /* Check msdos magic signature */
+ if(!msdos_magic_present(ebr))
+ return;
+ ebr_seen += 1;
+
+ struct part_entry *ptab_child = (struct part_entry *)(ebr + PARTITION_TABLES_OFFSET);
+
+ /* First process the data partitions */
+ for (int i = 0; i < 4; i++) {
+ if (*error)
+ return;
+
+ if (ptab_child[i].start_sect > 0) {
+ if (is_extended_partition(&ptab_child[i])) {
+ continue;
+ }
+
+ /* Check for garbage in the 3rd and 4th entries */
+ if (i > 2) {
+ unsigned int offset = ptab_child->start_lba + ptab_root->start_lba;
+ if ( offset + ptab_child->length <= ptab_root->start_lba ||
+ offset >= ptab_root->start_lba + ptab_root->length ) {
+ continue;
+ }
+ }
+ callback(drive_info,
+ &ptab_child[i],
+ ptab_root,
+ offset_root,
+ i,
+ ebr_seen);
+ }
+ }
+
+ /* Now process the extended partitions */
+ for (int i = 0; i < 4; i++) {
+ if (is_extended_partition(&ptab_child[i])) {
+ callback(drive_info,
+ &ptab_child[i],
+ ptab_root,
+ offset_root,
+ i,
+ ebr_seen);
+ process_ebr(drive_info, &ptab_child[i], ebr_seen + 1, callback, error, ptab_root->start_lba);
+ }
+ }
+}
+
+/**
+ * process_mbr - execute a callback for each partition contained in an {m,e}br
+ * @drive_info: driveinfo struct describing the drive
+ * @ptab: Pointer to the partition table
+ * @callback: Callback to execute
+ * @error: Return the error code (I/O), if needed
+ **/
+static void process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
+ void *callback(struct driveinfo *, struct part_entry *, struct part_entry *, int, int, int),
+ int *error)
+{
+ for (int i = 0; i < 4; i++) {
+ if (*error)
+ return;
+
+ if (ptab[i].start_sect > 0) {
+ if (is_extended_partition(&ptab[i])) {
+ callback(drive_info,
+ &ptab[i],
+ ptab,
+ 0,
+ i,
+ 0);
+ process_ebr(drive_info, &ptab[i], 0, callback, error, 0);
+ } else
+ callback(drive_info,
+ &ptab[i],
+ ptab,
+ 0,
+ i,
+ 0);
+ }
+ }
+}
+
+/**
+ * parse_partition_table - execute a callback for each partition entry
+ * @d: driveinfo struct describing the drive
+ * @callback: Callback to execute
+ * @error: Return the error code (I/O), if needed
+ *
+ * The signature of the callback should be the following:
+ *
+ * void callback(struct driveinfo *drive_info,
+ * struct part_entry *ptab,
+ * struct part_entry *ptab_root,
+ * int offset_root,
+ * int local_partition_number,
+ * int ebr_seen)
+ **/
+int parse_partition_table(struct driveinfo *d, void *callback, int *error)
+{
+ char *mbr = read_mbr(d->disk, error);
+ if (!mbr)
+ return -1;
+ else {
+ /* Check msdos magic signature */
+ if (!msdos_magic_present(mbr))
+ return -1;
+
+ struct part_entry *ptab = (struct part_entry *)(mbr + PARTITION_TABLES_OFFSET);
+ process_mbr(d, ptab, callback, error);
+ if (*error)
+ return -1;
+ else
+ return 0;
+ }
+}