/* ----------------------------------------------------------------------- * * * Copyright 2009 Pierre-Alexandre Meyer * * Some parts borrowed from chain.c32: * * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved * Copyright 2009 Intel Corporation; author: H. Peter Anvin * * This file is part of Syslinux, and is made available under * the terms of the GNU General Public License version 2. * * ----------------------------------------------------------------------- */ #include #include #include #include #include #include static int is_extended_partition(struct part_entry *ptab) { return (ptab->ostype == 0x05 || ptab->ostype == 0x0f || ptab->ostype == 0x85); } static int msdos_magic_present(const char *ptab) { return (*(uint16_t *) (ptab + 0x1fe) == 0xaa55); } /** * process_extended_partition - execute a callback for each partition contained listed in an ebr * @drive_info: driveinfo struct describing the drive * @partition_offset: Absolute start (lba) of the extended partition * @ebr_offset: Relative start (lba) of the current ebr processed within * the extended partition * @callback: Callback to execute * @error: Buffer for I/O errors * @nb_part_seen: Number of partitions found on the disk so far **/ static int process_extended_partition(struct driveinfo *drive_info, const int partition_offset, const int ebr_offset, p_callback callback, int nb_part_seen) { int status = 0; /* The ebr is located at the first sector of the extended partition */ char *ebr = malloc(SECTOR * sizeof(char)); if (read_sectors(drive_info, ebr, partition_offset + ebr_offset, 1) == -1) goto abort; /* Check msdos magic signature */ if (!msdos_magic_present(ebr)) goto abort; struct part_entry *ptab = (struct part_entry *)(ebr + PARTITION_TABLES_OFFSET); for (int i = 0; i < 4; i++) { if (status == -1) goto abort; if (!is_extended_partition(&ptab[i])) { /* * This EBR partition table entry points to the * logical partition associated to that EBR */ int logical_partition_start = ebr_offset + ptab[i].start_lba; /* Last EBR in the extended partition? */ if (!logical_partition_start) continue; /* * Check for garbage: * 3rd and 4th entries in an EBR should be zero * Some (malformed) partitioning software still add some * data partitions there. */ if (ptab[i].start_lba <= 0 || ptab[i].length <= 0) continue; nb_part_seen++; callback(drive_info, &ptab[i], partition_offset + logical_partition_start, nb_part_seen); } else status = process_extended_partition(drive_info, partition_offset, ptab[i].start_lba, callback, nb_part_seen); } free(ebr); return 0; abort: free(ebr); return -1; } /** * 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 **/ static int process_mbr(struct driveinfo *drive_info, struct part_entry *ptab, p_callback callback) { int status = 0; for (int i = 0; i < 4; i++) { if (status == -1) return -1; if (ptab[i].start_sect > 0) { if (is_extended_partition(&ptab[i])) { callback(drive_info, &ptab[i], ptab[i].start_lba, i + 1); status = process_extended_partition(drive_info, ptab[i].start_lba, 0, callback, 4); } else callback(drive_info, &ptab[i], ptab[i].start_lba, i + 1); } } return 0; } /** * parse_partition_table - execute a callback for each partition entry * @d: driveinfo struct describing the drive * @callback: Callback to execute * * The signature of the callback should be the following: * * void callback(struct driveinfo *drive_info, * struct part_entry *ptab, * int offset_root, * int nb_part_seen) **/ int parse_partition_table(struct driveinfo *d, p_callback callback) { char *mbr = malloc(SECTOR * sizeof(char)); if (read_mbr(d->disk, mbr) == -1) 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); return process_mbr(d, ptab, callback); } }