[syslinux] [RFC/PATCH 1/3] Move partiter from com32/chain to com32/lib/syslinux

Raphael S.Carvalho raphael.scarv at gmail.com
Thu Oct 17 22:39:59 PDT 2013


From: Raphael S. Carvalho <raphael.scarv at gmail.com>

MultiFS depends on the availability of partiter to find a partition.

Signed-off-by: Raphael S. Carvalho <raphael.scarv at gmail.com>
---
 com32/chain/Makefile              |    2 +-
 com32/chain/chain.c               |    4 +-
 com32/chain/mangle.c              |    4 +-
 com32/chain/mangle.h              |    2 +-
 com32/chain/options.c             |    4 +-
 com32/chain/partiter.c            |  656 -------------------------------------
 com32/chain/partiter.h            |  124 -------
 com32/chain/utility.c             |  256 ---------------
 com32/chain/utility.h             |   75 -----
 com32/include/syslinux/partiter.h |  124 +++++++
 com32/include/syslinux/utility.h  |   76 +++++
 com32/lib/syslinux/partiter.c     |  656 +++++++++++++++++++++++++++++++++++++
 com32/lib/syslinux/utility.c      |  256 +++++++++++++++
 mk/lib.mk                         |    2 +-
 14 files changed, 1121 insertions(+), 1120 deletions(-)
 delete mode 100644 com32/chain/partiter.c
 delete mode 100644 com32/chain/partiter.h
 delete mode 100644 com32/chain/utility.c
 delete mode 100644 com32/chain/utility.h
 create mode 100644 com32/include/syslinux/partiter.h
 create mode 100644 com32/include/syslinux/utility.h
 create mode 100644 com32/lib/syslinux/partiter.c
 create mode 100644 com32/lib/syslinux/utility.c

diff --git a/com32/chain/Makefile b/com32/chain/Makefile
index 4a5af91..dcc60f5 100644
--- a/com32/chain/Makefile
+++ b/com32/chain/Makefile
@@ -16,7 +16,7 @@
 VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
-OBJS = chain.o partiter.o utility.o options.o mangle.o
+OBJS = chain.o options.o mangle.o
 CFLAGS += -fno-strict-aliasing
 
 all: chain.c32
diff --git a/com32/chain/chain.c b/com32/chain/chain.c
index ae95d45..dce44df 100644
--- a/com32/chain/chain.c
+++ b/com32/chain/chain.c
@@ -35,9 +35,9 @@
 #include <syslinux/disk.h>
 #include <syslinux/video.h>
 #include "chain.h"
-#include "utility.h"
+#include <syslinux/utility.h>
 #include "options.h"
-#include "partiter.h"
+#include <syslinux/partiter.h>
 #include "mangle.h"
 
 static int fixed_cnt = 128;   /* see comments in main() */
diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
index ffdaab8..72eafde 100644
--- a/com32/chain/mangle.c
+++ b/com32/chain/mangle.c
@@ -37,8 +37,8 @@
 #include <syslinux/config.h>
 #include "chain.h"
 #include "options.h"
-#include "utility.h"
-#include "partiter.h"
+#include <syslinux/utility.h>
+#include <syslinux/partiter.h>
 #include "mangle.h"
 
 static const char cmldr_signature[8] = "cmdcons";
diff --git a/com32/chain/mangle.h b/com32/chain/mangle.h
index d4a5b75..df5c568 100644
--- a/com32/chain/mangle.h
+++ b/com32/chain/mangle.h
@@ -32,7 +32,7 @@
 #define COM32_CHAIN_MANGLE_H
 
 #include "chain.h"
-#include "partiter.h"
+#include <syslinux/partiter.h>
 
 /* file's manglers */
 int manglef_isolinux(struct data_area *data);
diff --git a/com32/chain/options.c b/com32/chain/options.c
index 4e722a0..4211c2f 100644
--- a/com32/chain/options.c
+++ b/com32/chain/options.c
@@ -33,8 +33,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include "chain.h"
-#include "partiter.h"
-#include "utility.h"
+#include <syslinux/partiter.h>
+#include <syslinux/utility.h>
 #include "options.h"
 
 struct options opt;
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
deleted file mode 100644
index 1eb5350..0000000
--- a/com32/chain/partiter.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright 2010 Shao Miller
- *   Copyright 2010-2012 Michal Soltys
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * partiter.c
- *
- * Provides disk / partition iteration.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <zlib.h>
-#include <syslinux/disk.h>
-#include "partiter.h"
-#include "utility.h"
-
-#define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85)
-#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
-#define sane(s,l) ((s)+(l) > (s))
-
-/* virtual forwards */
-
-static void pi_dtor_(struct part_iter *);
-static int  pi_next_(struct part_iter *);
-static int  pi_dos_next(struct part_iter *);
-static int  pi_gpt_next(struct part_iter *);
-
-/* vtab and types */
-
-static struct itertype types[] = {
-   [0] = {
-	.dtor = &pi_dtor_,
-	.next = &pi_dos_next,
-}, [1] = {
-	.dtor = &pi_dtor_,
-	.next = &pi_gpt_next,
-}, [2] = {
-	.dtor = &pi_dtor_,
-	.next = &pi_next_,
-}};
-
-const struct itertype * const typedos = types;
-const struct itertype * const typegpt = types+1;
-const struct itertype * const typeraw = types+2;
-
-/* pi_dtor_() - common/raw iterator cleanup */
-static void pi_dtor_(struct part_iter *iter)
-{
-    /* syslinux's free is null resilient */
-    free(iter->data);
-}
-
-/* pi_ctor() - common/raw iterator initialization */
-static int pi_ctor(struct part_iter *iter,
-	const struct disk_info *di, int flags
-)
-{
-    memcpy(&iter->di, di, sizeof *di);
-    iter->flags = flags;
-    iter->index0 = -1;
-    iter->length = di->lbacnt;
-
-    iter->type = typeraw;
-    return 0;
-}
-
-/* pi_dos_ctor() - MBR/EBR iterator specific initialization */
-static int pi_dos_ctor(struct part_iter *iter,
-	const struct disk_info *di, int flags,
-	const struct disk_dos_mbr *mbr
-)
-{
-    if (pi_ctor(iter, di, flags))
-	return -1;
-
-    if (!(iter->data = malloc(sizeof *mbr))) {
-	critm();
-	goto bail;
-    }
-
-    memcpy(iter->data, mbr, sizeof *mbr);
-
-    iter->dos.bebr_index0 = -1;
-    iter->dos.disk_sig = mbr->disk_sig;
-
-    iter->type = typedos;
-    return 0;
-bail:
-    pi_dtor_(iter);
-    return -1;
-}
-
-/* pi_gpt_ctor() - GPT iterator specific initialization */
-static int pi_gpt_ctor(struct part_iter *iter,
-	const struct disk_info *di, int flags,
-	const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl
-)
-{
-    uint64_t siz;
-
-    if (pi_ctor(iter, di, flags))
-	return -1;
-
-    siz = (uint64_t)gpth->part_count * gpth->part_size;
-
-    if (!(iter->data = malloc((size_t)siz))) {
-	critm();
-	goto bail;
-    }
-
-    memcpy(iter->data, gptl, (size_t)siz);
-
-    iter->gpt.pe_count = (int)gpth->part_count;
-    iter->gpt.pe_size = (int)gpth->part_size;
-    iter->gpt.ufirst = gpth->lba_first_usable;
-    iter->gpt.ulast = gpth->lba_last_usable;
-
-    memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
-    memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
-
-    iter->type = typegpt;
-    return 0;
-bail:
-    pi_dtor_(iter);
-    return -1;
-}
-
-/* Logical partition must be sane, meaning:
- * - must be data or empty
- * - must have non-0 start and length
- * - values must not wrap around 32bit
- * - must be inside current EBR frame
- */
-
-static int notsane_logical(const struct part_iter *iter)
-{
-    const struct disk_dos_part_entry *dp;
-    uint32_t end_log;
-
-    dp = ((struct disk_dos_mbr *)iter->data)->table;
-
-    if (!dp[0].ostype)
-	return 0;
-
-    if (ost_is_ext(dp[0].ostype)) {
-	error("The 1st EBR entry must be data or empty.");
-	return -1;
-    }
-
-    if (iter->flags & PIF_RELAX)
-	return 0;
-
-    end_log = dp[0].start_lba + dp[0].length;
-
-    if (!dp[0].start_lba ||
-	!dp[0].length ||
-	!sane(dp[0].start_lba, dp[0].length) ||
-	end_log > iter->dos.nebr_siz) {
-
-	error("Logical partition (in EBR) with invalid offset and/or length.");
-	return -1;
-    }
-
-    return 0;
-}
-
-/* Extended partition must be sane, meaning:
- * - must be extended or empty
- * - must have non-0 start and length
- * - values must not wrap around 32bit
- * - must be inside base EBR frame
- */
-
-static int notsane_extended(const struct part_iter *iter)
-{
-    const struct disk_dos_part_entry *dp;
-    uint32_t end_ebr;
-
-    dp = ((struct disk_dos_mbr *)iter->data)->table;
-
-    if (!dp[1].ostype)
-	return 0;
-
-    if (!ost_is_nondata(dp[1].ostype)) {
-	error("The 2nd EBR entry must be extended or empty.");
-	return -1;
-    }
-
-    if (iter->flags & PIF_RELAX)
-	return 0;
-
-    end_ebr = dp[1].start_lba + dp[1].length;
-
-    if (!dp[1].start_lba ||
-	!dp[1].length ||
-	!sane(dp[1].start_lba, dp[1].length) ||
-	end_ebr > iter->dos.bebr_siz) {
-
-	error("Extended partition (EBR) with invalid offset and/or length.");
-	return -1;
-    }
-
-    return 0;
-}
-
-/* Primary partition must be sane, meaning:
- * - must have non-0 start and length
- * - values must not wrap around 32bit
- */
-
-static int notsane_primary(const struct part_iter *iter)
-{
-    const struct disk_dos_part_entry *dp;
-    dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
-
-    if (!dp->ostype)
-	return 0;
-
-    if (iter->flags & PIF_RELAX)
-	return 0;
-
-    if (!dp->start_lba ||
-	!dp->length ||
-	!sane(dp->start_lba, dp->length) ||
-	dp->start_lba + dp->length > iter->di.lbacnt) {
-	error("Primary partition (in MBR) with invalid offset and/or length.");
-	return -1;
-    }
-
-    return 0;
-}
-
-static int notsane_gpt(const struct part_iter *iter)
-{
-    const struct disk_gpt_part_entry *gp;
-    gp = (const struct disk_gpt_part_entry *)
-	(iter->data + iter->index0 * iter->gpt.pe_size);
-
-    if (guid_is0(&gp->type))
-	return 0;
-
-    if (iter->flags & PIF_RELAX)
-	return 0;
-
-    if (gp->lba_first < iter->gpt.ufirst ||
-	gp->lba_last > iter->gpt.ulast) {
-	error("LBA sectors of GPT partition are beyond the range allowed in GPT header.");
-	return -1;
-    }
-
-    return 0;
-}
-
-static int dos_next_mbr(struct part_iter *iter, uint32_t *lba,
-			    struct disk_dos_part_entry **_dp)
-{
-    struct disk_dos_part_entry *dp;
-
-    while (++iter->index0 < 4) {
-	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
-
-	if (notsane_primary(iter)) {
-	    iter->status = PI_INSANE;
-	    return -1;
-	}
-
-	if (ost_is_ext(dp->ostype)) {
-	    if (iter->dos.bebr_index0 >= 0) {
-		error("More than 1 extended partition.");
-		iter->status = PI_INSANE;
-		return -1;
-	    }
-	    /* record base EBR index */
-	    iter->dos.bebr_index0 = iter->index0;
-	}
-	if (!ost_is_nondata(dp->ostype) || (iter->flags & PIF_STEPALL)) {
-	    *lba = dp->start_lba;
-	    *_dp = dp;
-	    break;
-	}
-    }
-
-    return 0;
-}
-
-static int prep_base_ebr(struct part_iter *iter)
-{
-    struct disk_dos_part_entry *dp;
-
-    if (iter->dos.bebr_index0 < 0)	/* if we don't have base extended partition at all */
-	return -1;
-    else if (!iter->dos.bebr_lba) { /* if not initialized yet */
-	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->dos.bebr_index0;
-
-	iter->dos.bebr_lba = dp->start_lba;
-	iter->dos.bebr_siz = dp->length;
-
-	iter->dos.nebr_lba = dp->start_lba;
-	iter->dos.nebr_siz = dp->length;
-
-	iter->index0--;
-    }
-    return 0;
-}
-
-static int dos_next_ebr(struct part_iter *iter, uint32_t *lba,
-			    struct disk_dos_part_entry **_dp)
-{
-    struct disk_dos_part_entry *dp;
-
-    if (prep_base_ebr(iter) < 0) {
-	iter->status = PI_DONE;
-	return -1;
-    }
-
-    while (++iter->index0 < 1024 && iter->dos.nebr_lba) {
-	free(iter->data);
-	if (!(iter->data =
-		    disk_read_sectors(&iter->di, iter->dos.nebr_lba, 1))) {
-	    error("Couldn't load EBR.");
-	    iter->status = PI_ERRLOAD;
-	    return -1;
-	}
-
-	/* check sanity of loaded data */
-	if (notsane_logical(iter) || notsane_extended(iter)) {
-	    iter->status = PI_INSANE;
-	    return -1;
-	}
-
-	dp = ((struct disk_dos_mbr *)iter->data)->table;
-
-	iter->dos.cebr_lba = iter->dos.nebr_lba;
-	iter->dos.cebr_siz = iter->dos.nebr_siz;
-
-	/* setup next frame values */
-	if (dp[1].ostype) {
-	    iter->dos.nebr_lba = iter->dos.bebr_lba + dp[1].start_lba;
-	    iter->dos.nebr_siz = dp[1].length;
-	} else {
-	    iter->dos.nebr_lba = 0;
-	    iter->dos.nebr_siz = 0;
-	}
-
-	if (!dp[0].ostype)
-	    iter->dos.logskipcnt++;
-
-	if (dp[0].ostype || (iter->flags & PIF_STEPALL)) {
-	    *lba = dp[0].start_lba ? iter->dos.cebr_lba + dp[0].start_lba : 0;
-	    *_dp = dp;
-	    return 0;
-	}
-	/*
-	 * This way it's possible to continue, if some crazy soft left a "hole"
-	 * - EBR with a valid extended partition without a logical one. In
-	 * such case, linux will not reserve a number for such hole - so we
-	 * don't increase index0. If PIF_STEPALL flag is set, we will never
-	 * reach this place.
-	 */
-    }
-    iter->status = PI_DONE;
-    return -1;
-}
-
-static void gpt_conv_label(struct part_iter *iter)
-{
-    const struct disk_gpt_part_entry *gp;
-    const int16_t *orig_lab;
-
-    gp = (const struct disk_gpt_part_entry *)
-	(iter->data + iter->index0 * iter->gpt.pe_size);
-    orig_lab = (const int16_t *)gp->name;
-
-    /* caveat: this is very crude conversion */
-    for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
-	iter->gpt.part_label[i] = (char)orig_lab[i];
-    }
-    iter->gpt.part_label[PI_GPTLABSIZE/2] = 0;
-}
-
-static inline int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz)
-{
-    return crc == crc32(crc32(0, NULL, 0), buf, siz);
-}
-
-static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh)
-{
-    struct disk_gpt_header *gh = *_gh;
-    uint64_t lba_alt;
-    uint32_t hold_crc32;
-
-    hold_crc32 = gh->chksum;
-    gh->chksum = 0;
-    if (!valid_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
-	warn("Primary GPT header checksum invalid.");
-	/* retry with backup */
-	lba_alt = gh->lba_alt;
-	free(gh);
-	if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) {
-	    error("Couldn't read backup GPT header.");
-	    return -1;
-	}
-	hold_crc32 = gh->chksum;
-	gh->chksum = 0;
-	if (!valid_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
-	    error("Secondary GPT header checksum invalid.");
-	    return -1;
-	}
-    }
-    /* restore old checksum */
-    gh->chksum = hold_crc32;
-
-    return 0;
-}
-
-static int pi_next_(struct part_iter *iter)
-{
-    iter->status = PI_DONE;
-    return iter->status;
-}
-
-static int pi_dos_next(struct part_iter *iter)
-{
-    uint32_t abs_lba = 0;
-    struct disk_dos_part_entry *dos_part = NULL;
-
-    if (iter->status)
-	return iter->status;
-
-    /* look for primary partitions */
-    if (iter->index0 < 4 &&
-	    dos_next_mbr(iter, &abs_lba, &dos_part) < 0)
-	return iter->status;
-
-    /* look for logical partitions */
-    if (iter->index0 >= 4 &&
-	    dos_next_ebr(iter, &abs_lba, &dos_part) < 0)
-	return iter->status;
-
-    /*
-     * note special index handling:
-     * in case PIF_STEPALL is set - this makes the index consistent with
-     * non-PIF_STEPALL iterators
-     */
-
-    if (!dos_part->ostype)
-	iter->index = -1;
-    else
-	iter->index = iter->index0 + 1 - iter->dos.logskipcnt;
-    iter->abs_lba = abs_lba;
-    iter->length = dos_part->length;
-    iter->record = (char *)dos_part;
-
-#ifdef DEBUG
-    disk_dos_part_dump(dos_part);
-#endif
-
-    return iter->status;
-}
-
-static int pi_gpt_next(struct part_iter *iter)
-{
-    const struct disk_gpt_part_entry *gpt_part = NULL;
-
-    if (iter->status)
-	return iter->status;
-
-    while (++iter->index0 < iter->gpt.pe_count) {
-	gpt_part = (const struct disk_gpt_part_entry *)
-	    (iter->data + iter->index0 * iter->gpt.pe_size);
-
-	if (notsane_gpt(iter)) {
-	    iter->status = PI_INSANE;
-	    return iter->status;
-	}
-
-	if (!guid_is0(&gpt_part->type) || (iter->flags & PIF_STEPALL))
-	    break;
-    }
-    /* no more partitions ? */
-    if (iter->index0 == iter->gpt.pe_count) {
-	iter->status = PI_DONE;
-	return iter->status;
-    }
-    /* gpt_part is guaranteed to be valid here */
-    iter->index = iter->index0 + 1;
-    iter->abs_lba = gpt_part->lba_first;
-    iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
-    iter->record = (char *)gpt_part;
-    memcpy(&iter->gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
-    gpt_conv_label(iter);
-
-#ifdef DEBUG
-    disk_gpt_part_dump(gpt_part);
-#endif
-
-    return iter->status;
-}
-
-static struct part_iter *pi_alloc(void)
-{
-    struct part_iter *iter;
-    if (!(iter = malloc(sizeof *iter)))
-	critm();
-    else
-	memset(iter, 0, sizeof *iter);
-    return iter;
-}
-
-/* pi_del() - delete iterator */
-void pi_del(struct part_iter **_iter)
-{
-    if(!_iter || !*_iter)
-	return;
-    pi_dtor(*_iter);
-    free(*_iter);
-    *_iter = NULL;
-}
-
-/* pi_begin() - validate and and get proper iterator for a disk described by di */
-struct part_iter *pi_begin(const struct disk_info *di, int flags)
-{
-    int gptprot, ret = -1;
-    struct part_iter *iter;
-    struct disk_dos_mbr *mbr = NULL;
-    struct disk_gpt_header *gpth = NULL;
-    struct disk_gpt_part_entry *gptl = NULL;
-
-    /* Preallocate iterator */
-    if (!(iter = pi_alloc()))
-	goto bail;
-
-    /* Read MBR */
-    if (!(mbr = disk_read_sectors(di, 0, 1))) {
-	error("Couldn't read the first disk sector.");
-	goto bail;
-    }
-
-    /* Check for MBR magic */
-    if (mbr->sig != disk_mbr_sig_magic) {
-	warn("No MBR magic, treating disk as raw.");
-	/* looks like RAW */
-	ret = pi_ctor(iter, di, flags);
-	goto bail;
-    }
-
-    /* Check for GPT protective MBR */
-    gptprot = 0;
-    for (size_t i = 0; i < 4; i++)
-	gptprot |= (mbr->table[i].ostype == 0xEE);
-    if (gptprot && !(flags & PIF_PREFMBR)) {
-	if (!(gpth = disk_read_sectors(di, 1, 1))) {
-	    error("Couldn't read potential GPT header.");
-	    goto bail;
-	}
-    }
-
-    if (gpth && gpth->rev.uint32 == 0x00010000 &&
-	    !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) {
-	/* looks like GPT v1.0 */
-	uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
-	uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
-	uint64_t gpt_lcnt;	    /* size of GPT partition in sectors */
-#ifdef DEBUG
-	dprintf("Looks like a GPT v1.0 disk.\n");
-	disk_gpt_header_dump(gpth);
-#endif
-	/* Verify checksum, fallback to backup, then bail if invalid */
-	if (gpt_check_hdr_crc(di, &gpth))
-	    goto bail;
-
-	gpt_loff = gpth->lba_table;
-	gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
-	gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
-
-	/*
-	 * disk_read_sectors allows reading of max 255 sectors, so we use
-	 * it as a sanity check base. EFI doesn't specify max (AFAIK).
-	 * Apart from that, some extensive sanity checks.
-	 */
-	if (!(flags & PIF_RELAX) && (
-		!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u ||
-		gpth->lba_first_usable > gpth->lba_last_usable ||
-		!sane(gpt_loff, gpt_lcnt) ||
-		gpt_loff + gpt_lcnt > gpth->lba_first_usable ||
-		!sane(gpth->lba_last_usable, gpt_lcnt) ||
-		gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt ||
-		gpth->lba_alt >= di->lbacnt ||
-		gpth->part_size < sizeof *gptl)) {
-	    error("Invalid GPT header's values.");
-	    goto bail;
-	}
-	if (!(gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt))) {
-	    error("Couldn't read GPT partition list.");
-	    goto bail;
-	}
-	/* Check array checksum(s). */
-	if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
-	    warn("Checksum of the main GPT partition list is invalid, trying backup.");
-	    free(gptl);
-	    /* secondary array directly precedes secondary header */
-	    if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, gpt_lcnt))) {
-		error("Couldn't read backup GPT partition list.");
-		goto bail;
-	    }
-	    if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) {
-		error("Checksum of the backup GPT partition list is invalid, giving up.");
-		goto bail;
-	    }
-	}
-	/* looks like GPT */
-	ret = pi_gpt_ctor(iter, di, flags, gpth, gptl);
-    } else {
-	/* looks like MBR */
-	ret = pi_dos_ctor(iter, di, flags, mbr);
-    }
-bail:
-    if (ret < 0)
-	free(iter);
-    free(mbr);
-    free(gpth);
-    free(gptl);
-
-    return iter;
-}
-
-/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
deleted file mode 100644
index 13dec84..0000000
--- a/com32/chain/partiter.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright 2010 Shao Miller
- *   Copyright 2010-2012 Michal Soltys
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * partiter.h
- *
- * Provides disk / partition iteration.
- */
-
-#ifndef COM32_CHAIN_PARTITER_H
-#define COM32_CHAIN_PARTITER_H
-
-#include <stdint.h>
-#include <syslinux/disk.h>
-
-/* status */
-
-enum {PI_OK, PI_DONE, PI_INSANE, PI_ERRLOAD};
-
-/* flags */
-
-enum {PIF_STEPALL = 1, PIF_RELAX = 2, PIF_PREFMBR = 4};
-
-struct itertype;
-struct part_iter;
-
-struct itertype {
-	void (*dtor)(struct part_iter *);
-	int  (*next)(struct part_iter *);
-};
-
-#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name))
-
-struct part_iter {
-    const struct itertype *type;
-    char *data;
-    char *record;
-    uint64_t abs_lba;
-    uint64_t length;
-    int index0;	    /* including holes, from -1 (disk, then parts from 0) */
-    int index;	    /* excluding holes, from  0 (disk, then parts from 1), -1 means hole, if PIF_STEPALL is set */
-    int flags;	    /* flags, see #defines above */
-    int status;	    /* current status, see enums above */
-    struct disk_info di;
-    union {
-	struct {
-	    uint32_t disk_sig;	  /* 32bit disk signature as stored in MBR */
-
-	    uint32_t bebr_lba;	  /* absolute lba of base extended partition */
-	    uint32_t bebr_siz;	  /* size of base extended partition */
-
-	    uint32_t cebr_lba;	  /* absolute lba of curr ext. partition */
-	    uint32_t cebr_siz;	  /* size of curr ext. partition */
-	    uint32_t nebr_lba;	  /* absolute lba of next ext. partition */
-	    uint32_t nebr_siz;	  /* size of next ext. partition */
-
-	    int bebr_index0;	  /* index of (0-3) of base ext. part., -1 if not present in MBR */
-	    int logskipcnt;	  /* how many logical holes were skipped */
-	} dos;
-	struct {
-	    struct guid disk_guid;
-	    struct guid part_guid;
-	    char part_label[PI_GPTLABSIZE/2+1];
-	    int pe_count;
-	    int pe_size;
-	    uint64_t ufirst;
-	    uint64_t ulast;
-	} gpt;
-    };
-};
-
-extern const struct itertype * const typedos;
-extern const struct itertype * const typegpt;
-extern const struct itertype * const typeraw;
-
-struct part_iter *pi_begin(const struct disk_info *, int flags);
-void pi_del(struct part_iter **);
-
-static inline int pi_errored(struct part_iter *iter)
-{
-    return iter->status > PI_DONE;
-}
-
-/* inline virtuals */
-static inline int pi_next(struct part_iter *iter)
-{
-    return iter->type->next(iter);
-}
-
-static inline void pi_dtor(struct part_iter *iter)
-{
-    iter->type->dtor(iter);
-}
-
-#endif
-
-/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/utility.c b/com32/chain/utility.c
deleted file mode 100644
index b17997f..0000000
--- a/com32/chain/utility.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright 2010 Shao Miller
- *   Copyright 2010-2012 Michal Soltys
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-#include <com32.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <fs.h>
-#include <syslinux/disk.h>
-#include <syslinux/pmapi.h>
-#include "utility.h"
-
-static const char *bpbtypes[] = {
-    [0] =  "unknown",
-    [1] =  "2.0",
-    [2] =  "3.0",
-    [3] =  "3.2",
-    [4] =  "3.4",
-    [5] =  "4.0",
-    [6] =  "8.0 (NT+)",
-    [7] =  "7.0",
-    [8] =  "exFAT",
-};
-
-void wait_key(void)
-{
-    int cnt;
-    char junk;
-
-    /* drain */
-    do {
-	errno = 0;
-	cnt = read(0, &junk, 1);
-    } while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
-
-    /* wait */
-    do {
-	errno = 0;
-	cnt = read(0, &junk, 1);
-    } while (!cnt || (cnt < 0 && errno == EAGAIN));
-}
-
-int guid_is0(const struct guid *guid)
-{
-    return
-	!(guid->data1 ||
-	  guid->data2 ||
-	  guid->data3 ||
-	  guid->data4);
-}
-
-/*
- * mode explanation:
- *
- * cnul - "strict" mode, never returning higher value than obtained from cbios
- * cadd - if the disk is larger than reported geometry /and/ if the geometry has
- *        less cylinders than 1024 - it means that the total size is somewhere
- *        between cs and cs+1; in this particular case, we bump the cs to be able
- *        to return matching chs triplet
- * cmax - assume we can use any cylinder value
- *
- * by default cadd seems most reasonable, giving consistent results with e.g.
- * sfdisk's behavior
- */
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode)
-{
-    uint32_t c, h, s, t;
-    uint32_t cs, hs, ss;
-
-    /*
-     * Not much reason here, but if we have no valid CHS geometry, we assume
-     * "typical" ones to have something to return.
-     */
-    if (di->cbios) {
-	cs = di->cyl;
-	hs = di->head;
-	ss = di->spt;
-	if (mode == L2C_CADD) {
-	    if (cs < 1024 && di->lbacnt > cs*hs*ss)
-		cs++;
-	} else if (mode == L2C_CMAX)
-	    cs = 1024;
-    } else {
-	if (di->disk & 0x80) {
-	    cs = 1024;
-	    hs = 255;
-	    ss = 63;
-	} else {
-	    cs = 80;
-	    hs = 2;
-	    ss = 18;
-	}
-    }
-
-    if (lba >= cs*hs*ss) {
-	s = ss;
-	h = hs - 1;
-	c = cs - 1;
-    } else {
-	s = (lba % ss) + 1;
-	t = lba / ss;
-	h = t % hs;
-	c = t / hs;
-    }
-
-    (*dst)[0] = h;
-    (*dst)[1] = s | ((c & 0x300) >> 2);
-    (*dst)[2] = c;
-}
-
-uint32_t get_file_lba(const char *filename)
-{
-    struct com32_filedata fd;
-    uint32_t lba = 0;
-    int size = 65536;
-    char *buf;
-
-    buf = lmalloc(size);
-    if (!buf)
-	return 0;
-
-    /* Put the filename in the bounce buffer */
-    strlcpy(buf, filename, size);
-
-    if (open_file(buf, O_RDONLY, &fd) <= 0) {
-	goto fail;		/* Filename not found */
-    }
-
-    /* Since the first member is the LBA, we simply cast */
-    lba = *((uint32_t *) MK_PTR(0, fd.handle));
-
-    /* Call comapi_close() to free the structure */
-    close_file(fd.handle);
-
-fail:
-    lfree(buf);
-    return lba;
-}
-
-/* drive offset detection */
-int drvoff_detect(int type)
-{
-    if (bpbV40 <= type && type <= bpbVNT) {
-	return 0x24;
-    } else if (type == bpbV70) {
-	return 0x40;
-    } else if (type == bpbEXF) {
-	return 0x6F;
-    }
-
-    return -1;
-}
-
-/*
- * heuristics could certainly be improved
- */
-int bpb_detect(const uint8_t *sec, const char *tag)
-{
-    int a, b, c, jmp = -1, rev = 0;
-
-    /* exFAT mess first (media descriptor is 0 here) */
-    if (!memcmp(sec + 0x03, "EXFAT   ", 8)) {
-	rev = bpbEXF;
-	goto out;
-    }
-
-    /* media descriptor check */
-    if ((sec[0x15] & 0xF0) != 0xF0)
-	goto out;
-
-    if (sec[0] == 0xEB)	/* jump short */
-	jmp = 2 + *(int8_t *)(sec + 1);
-    else if (sec[0] == 0xE9) /* jump near */
-	jmp = 3 + *(int16_t *)(sec + 1);
-
-    if (jmp < 0)    /* no boot code at all ? */
-	goto nocode;
-
-    /* sanity */
-    if (jmp < 0x18 || jmp > 0x1F0)
-	goto out;
-
-    /* detect by jump */
-    if (jmp >= 0x18 && jmp < 0x1E)
-	rev = bpbV20;
-    else if (jmp >= 0x1E && jmp < 0x20)
-	rev = bpbV30;
-    else if (jmp >= 0x20 && jmp < 0x24)
-	rev = bpbV32;
-    else if (jmp >= 0x24 && jmp < 0x46)
-	rev = bpbV34;
-
-    /* TODO: some better V2 - V3.4 checks ? */
-
-    if (rev)
-	goto out;
-    /*
-     * BPB info:
-     * 2.0 ==       0x0B - 0x17
-     * 3.0 == 2.0 + 0x18 - 0x1D
-     * 3.2 == 3.0 + 0x1E - 0x1F
-     * 3.4 ==!2.0 + 0x18 - 0x23
-     * 4.0 == 3.4 + 0x24 - 0x45
-     *  NT ==~3.4 + 0x24 - 0x53
-     * 7.0 == 3.4 + 0x24 - 0x59
-     */
-
-nocode:
-    a = memcmp(sec + 0x03, "NTFS", 4);
-    b = memcmp(sec + 0x36, "FAT", 3);
-    c = memcmp(sec + 0x52, "FAT", 3);	/* ext. DOS 7+ bs */
-
-    if ((sec[0x26] & 0xFE) == 0x28 && !b) {
-	rev = bpbV40;
-    } else if (sec[0x26] == 0x80 && !a) {
-	rev = bpbVNT;
-    } else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
-	rev = bpbV70;
-    }
-
-out:
-    printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]);
-    return rev;
-}
-
-/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/utility.h b/com32/chain/utility.h
deleted file mode 100644
index 596017b..0000000
--- a/com32/chain/utility.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright 2010 Shao Miller
- *   Copyright 2010-2012 Michal Soltys
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-#ifndef COM32_CHAIN_UTILITY_H
-#define COM32_CHAIN_UTILITY_H
-
-#include <stdint.h>
-#include <stdio.h>
-#include <syslinux/disk.h>
-#include <syslinux/movebits.h>
-
-/* most (all ?) bpb "types" known to humankind as of 2012 */
-enum {bpbUNK, bpbV20, bpbV30, bpbV32, bpbV34, bpbV40, bpbVNT, bpbV70, bpbEXF};
-
-/* see utility.c for details */
-enum {L2C_CNUL, L2C_CADD, L2C_CMAX};
-
-/* first usable and first unusable offsets */
-#define dosmin ((addr_t)0x500u)
-#define dosmax ((addr_t)(*(uint16_t *) 0x413 << 10))
-
-void wait_key(void);
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode);
-uint32_t get_file_lba(const char *filename);
-int drvoff_detect(int type);
-int bpb_detect(const uint8_t *bpb, const char *tag);
-int guid_is0(const struct guid *guid);
-
-static inline int warn(const char *x)
-{
-    return fprintf(stderr, "WARN: %s\n", x);
-}
-
-static inline int error(const char *x)
-{
-    return fprintf(stderr, "ERR: %s\n", x);
-}
-
-static inline int crit(const char *x)
-{
-    return fprintf(stderr, "CRIT: %s @%s:%d\n", x, __FILE__, __LINE__);
-}
-
-#define critm()  crit("Malloc failure.")
-
-#endif
-
-/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/include/syslinux/partiter.h b/com32/include/syslinux/partiter.h
new file mode 100644
index 0000000..13dec84
--- /dev/null
+++ b/com32/include/syslinux/partiter.h
@@ -0,0 +1,124 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.h
+ *
+ * Provides disk / partition iteration.
+ */
+
+#ifndef COM32_CHAIN_PARTITER_H
+#define COM32_CHAIN_PARTITER_H
+
+#include <stdint.h>
+#include <syslinux/disk.h>
+
+/* status */
+
+enum {PI_OK, PI_DONE, PI_INSANE, PI_ERRLOAD};
+
+/* flags */
+
+enum {PIF_STEPALL = 1, PIF_RELAX = 2, PIF_PREFMBR = 4};
+
+struct itertype;
+struct part_iter;
+
+struct itertype {
+	void (*dtor)(struct part_iter *);
+	int  (*next)(struct part_iter *);
+};
+
+#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name))
+
+struct part_iter {
+    const struct itertype *type;
+    char *data;
+    char *record;
+    uint64_t abs_lba;
+    uint64_t length;
+    int index0;	    /* including holes, from -1 (disk, then parts from 0) */
+    int index;	    /* excluding holes, from  0 (disk, then parts from 1), -1 means hole, if PIF_STEPALL is set */
+    int flags;	    /* flags, see #defines above */
+    int status;	    /* current status, see enums above */
+    struct disk_info di;
+    union {
+	struct {
+	    uint32_t disk_sig;	  /* 32bit disk signature as stored in MBR */
+
+	    uint32_t bebr_lba;	  /* absolute lba of base extended partition */
+	    uint32_t bebr_siz;	  /* size of base extended partition */
+
+	    uint32_t cebr_lba;	  /* absolute lba of curr ext. partition */
+	    uint32_t cebr_siz;	  /* size of curr ext. partition */
+	    uint32_t nebr_lba;	  /* absolute lba of next ext. partition */
+	    uint32_t nebr_siz;	  /* size of next ext. partition */
+
+	    int bebr_index0;	  /* index of (0-3) of base ext. part., -1 if not present in MBR */
+	    int logskipcnt;	  /* how many logical holes were skipped */
+	} dos;
+	struct {
+	    struct guid disk_guid;
+	    struct guid part_guid;
+	    char part_label[PI_GPTLABSIZE/2+1];
+	    int pe_count;
+	    int pe_size;
+	    uint64_t ufirst;
+	    uint64_t ulast;
+	} gpt;
+    };
+};
+
+extern const struct itertype * const typedos;
+extern const struct itertype * const typegpt;
+extern const struct itertype * const typeraw;
+
+struct part_iter *pi_begin(const struct disk_info *, int flags);
+void pi_del(struct part_iter **);
+
+static inline int pi_errored(struct part_iter *iter)
+{
+    return iter->status > PI_DONE;
+}
+
+/* inline virtuals */
+static inline int pi_next(struct part_iter *iter)
+{
+    return iter->type->next(iter);
+}
+
+static inline void pi_dtor(struct part_iter *iter)
+{
+    iter->type->dtor(iter);
+}
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/include/syslinux/utility.h b/com32/include/syslinux/utility.h
new file mode 100644
index 0000000..a9347dd
--- /dev/null
+++ b/com32/include/syslinux/utility.h
@@ -0,0 +1,76 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_UTILITY_H
+#define COM32_CHAIN_UTILITY_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <syslinux/disk.h>
+#include <syslinux/movebits.h>
+#include <klibc/compiler.h>
+
+/* most (all ?) bpb "types" known to humankind as of 2012 */
+enum {bpbUNK, bpbV20, bpbV30, bpbV32, bpbV34, bpbV40, bpbVNT, bpbV70, bpbEXF};
+
+/* see utility.c for details */
+enum {L2C_CNUL, L2C_CADD, L2C_CMAX};
+
+/* first usable and first unusable offsets */
+#define dosmin ((addr_t)0x500u)
+#define dosmax ((addr_t)(*(uint16_t *) 0x413 << 10))
+
+void wait_key(void);
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode);
+uint32_t get_file_lba(const char *filename);
+int drvoff_detect(int type);
+int bpb_detect(const uint8_t *bpb, const char *tag);
+int guid_is0(const struct guid *guid);
+
+static inline int warn(const char *x)
+{
+    return fprintf(stderr, "WARN: %s\n", x);
+}
+
+static __unusedfunc int error(const char *x)
+{
+    return fprintf(stderr, "ERR: %s\n", x);
+}
+
+static inline int crit(const char *x)
+{
+    return fprintf(stderr, "CRIT: %s @%s:%d\n", x, __FILE__, __LINE__);
+}
+
+#define critm()  crit("Malloc failure.")
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/lib/syslinux/partiter.c b/com32/lib/syslinux/partiter.c
new file mode 100644
index 0000000..ca3f2fe
--- /dev/null
+++ b/com32/lib/syslinux/partiter.c
@@ -0,0 +1,656 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.c
+ *
+ * Provides disk / partition iteration.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <zlib.h>
+#include <syslinux/disk.h>
+#include <syslinux/partiter.h>
+#include <syslinux/utility.h>
+
+#define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85)
+#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
+#define sane(s,l) ((s)+(l) > (s))
+
+/* virtual forwards */
+
+static void pi_dtor_(struct part_iter *);
+static int  pi_next_(struct part_iter *);
+static int  pi_dos_next(struct part_iter *);
+static int  pi_gpt_next(struct part_iter *);
+
+/* vtab and types */
+
+static struct itertype types[] = {
+   [0] = {
+	.dtor = &pi_dtor_,
+	.next = &pi_dos_next,
+}, [1] = {
+	.dtor = &pi_dtor_,
+	.next = &pi_gpt_next,
+}, [2] = {
+	.dtor = &pi_dtor_,
+	.next = &pi_next_,
+}};
+
+const struct itertype * const typedos = types;
+const struct itertype * const typegpt = types+1;
+const struct itertype * const typeraw = types+2;
+
+/* pi_dtor_() - common/raw iterator cleanup */
+static void pi_dtor_(struct part_iter *iter)
+{
+    /* syslinux's free is null resilient */
+    free(iter->data);
+}
+
+/* pi_ctor() - common/raw iterator initialization */
+static int pi_ctor(struct part_iter *iter,
+	const struct disk_info *di, int flags
+)
+{
+    memcpy(&iter->di, di, sizeof *di);
+    iter->flags = flags;
+    iter->index0 = -1;
+    iter->length = di->lbacnt;
+
+    iter->type = typeraw;
+    return 0;
+}
+
+/* pi_dos_ctor() - MBR/EBR iterator specific initialization */
+static int pi_dos_ctor(struct part_iter *iter,
+	const struct disk_info *di, int flags,
+	const struct disk_dos_mbr *mbr
+)
+{
+    if (pi_ctor(iter, di, flags))
+	return -1;
+
+    if (!(iter->data = malloc(sizeof *mbr))) {
+	critm();
+	goto bail;
+    }
+
+    memcpy(iter->data, mbr, sizeof *mbr);
+
+    iter->dos.bebr_index0 = -1;
+    iter->dos.disk_sig = mbr->disk_sig;
+
+    iter->type = typedos;
+    return 0;
+bail:
+    pi_dtor_(iter);
+    return -1;
+}
+
+/* pi_gpt_ctor() - GPT iterator specific initialization */
+static int pi_gpt_ctor(struct part_iter *iter,
+	const struct disk_info *di, int flags,
+	const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl
+)
+{
+    uint64_t siz;
+
+    if (pi_ctor(iter, di, flags))
+	return -1;
+
+    siz = (uint64_t)gpth->part_count * gpth->part_size;
+
+    if (!(iter->data = malloc((size_t)siz))) {
+	critm();
+	goto bail;
+    }
+
+    memcpy(iter->data, gptl, (size_t)siz);
+
+    iter->gpt.pe_count = (int)gpth->part_count;
+    iter->gpt.pe_size = (int)gpth->part_size;
+    iter->gpt.ufirst = gpth->lba_first_usable;
+    iter->gpt.ulast = gpth->lba_last_usable;
+
+    memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
+    memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
+
+    iter->type = typegpt;
+    return 0;
+bail:
+    pi_dtor_(iter);
+    return -1;
+}
+
+/* Logical partition must be sane, meaning:
+ * - must be data or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside current EBR frame
+ */
+
+static int notsane_logical(const struct part_iter *iter)
+{
+    const struct disk_dos_part_entry *dp;
+    uint32_t end_log;
+
+    dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+    if (!dp[0].ostype)
+	return 0;
+
+    if (ost_is_ext(dp[0].ostype)) {
+	error("The 1st EBR entry must be data or empty.");
+	return -1;
+    }
+
+    if (iter->flags & PIF_RELAX)
+	return 0;
+
+    end_log = dp[0].start_lba + dp[0].length;
+
+    if (!dp[0].start_lba ||
+	!dp[0].length ||
+	!sane(dp[0].start_lba, dp[0].length) ||
+	end_log > iter->dos.nebr_siz) {
+
+	error("Logical partition (in EBR) with invalid offset and/or length.");
+	return -1;
+    }
+
+    return 0;
+}
+
+/* Extended partition must be sane, meaning:
+ * - must be extended or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside base EBR frame
+ */
+
+static int notsane_extended(const struct part_iter *iter)
+{
+    const struct disk_dos_part_entry *dp;
+    uint32_t end_ebr;
+
+    dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+    if (!dp[1].ostype)
+	return 0;
+
+    if (!ost_is_nondata(dp[1].ostype)) {
+	error("The 2nd EBR entry must be extended or empty.");
+	return -1;
+    }
+
+    if (iter->flags & PIF_RELAX)
+	return 0;
+
+    end_ebr = dp[1].start_lba + dp[1].length;
+
+    if (!dp[1].start_lba ||
+	!dp[1].length ||
+	!sane(dp[1].start_lba, dp[1].length) ||
+	end_ebr > iter->dos.bebr_siz) {
+
+	error("Extended partition (EBR) with invalid offset and/or length.");
+	return -1;
+    }
+
+    return 0;
+}
+
+/* Primary partition must be sane, meaning:
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ */
+
+static int notsane_primary(const struct part_iter *iter)
+{
+    const struct disk_dos_part_entry *dp;
+    dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
+
+    if (!dp->ostype)
+	return 0;
+
+    if (iter->flags & PIF_RELAX)
+	return 0;
+
+    if (!dp->start_lba ||
+	!dp->length ||
+	!sane(dp->start_lba, dp->length) ||
+	dp->start_lba + dp->length > iter->di.lbacnt) {
+	error("Primary partition (in MBR) with invalid offset and/or length.");
+	return -1;
+    }
+
+    return 0;
+}
+
+static int notsane_gpt(const struct part_iter *iter)
+{
+    const struct disk_gpt_part_entry *gp;
+    gp = (const struct disk_gpt_part_entry *)
+	(iter->data + iter->index0 * iter->gpt.pe_size);
+
+    if (guid_is0(&gp->type))
+	return 0;
+
+    if (iter->flags & PIF_RELAX)
+	return 0;
+
+    if (gp->lba_first < iter->gpt.ufirst ||
+	gp->lba_last > iter->gpt.ulast) {
+	error("LBA sectors of GPT partition are beyond the range allowed in GPT header.");
+	return -1;
+    }
+
+    return 0;
+}
+
+static int dos_next_mbr(struct part_iter *iter, uint32_t *lba,
+			    struct disk_dos_part_entry **_dp)
+{
+    struct disk_dos_part_entry *dp;
+
+    while (++iter->index0 < 4) {
+	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
+
+	if (notsane_primary(iter)) {
+	    iter->status = PI_INSANE;
+	    return -1;
+	}
+
+	if (ost_is_ext(dp->ostype)) {
+	    if (iter->dos.bebr_index0 >= 0) {
+		error("More than 1 extended partition.");
+		iter->status = PI_INSANE;
+		return -1;
+	    }
+	    /* record base EBR index */
+	    iter->dos.bebr_index0 = iter->index0;
+	}
+	if (!ost_is_nondata(dp->ostype) || (iter->flags & PIF_STEPALL)) {
+	    *lba = dp->start_lba;
+	    *_dp = dp;
+	    break;
+	}
+    }
+
+    return 0;
+}
+
+static int prep_base_ebr(struct part_iter *iter)
+{
+    struct disk_dos_part_entry *dp;
+
+    if (iter->dos.bebr_index0 < 0)	/* if we don't have base extended partition at all */
+	return -1;
+    else if (!iter->dos.bebr_lba) { /* if not initialized yet */
+	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->dos.bebr_index0;
+
+	iter->dos.bebr_lba = dp->start_lba;
+	iter->dos.bebr_siz = dp->length;
+
+	iter->dos.nebr_lba = dp->start_lba;
+	iter->dos.nebr_siz = dp->length;
+
+	iter->index0--;
+    }
+    return 0;
+}
+
+static int dos_next_ebr(struct part_iter *iter, uint32_t *lba,
+			    struct disk_dos_part_entry **_dp)
+{
+    struct disk_dos_part_entry *dp;
+
+    if (prep_base_ebr(iter) < 0) {
+	iter->status = PI_DONE;
+	return -1;
+    }
+
+    while (++iter->index0 < 1024 && iter->dos.nebr_lba) {
+	free(iter->data);
+	if (!(iter->data =
+		    disk_read_sectors(&iter->di, iter->dos.nebr_lba, 1))) {
+	    error("Couldn't load EBR.");
+	    iter->status = PI_ERRLOAD;
+	    return -1;
+	}
+
+	/* check sanity of loaded data */
+	if (notsane_logical(iter) || notsane_extended(iter)) {
+	    iter->status = PI_INSANE;
+	    return -1;
+	}
+
+	dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+	iter->dos.cebr_lba = iter->dos.nebr_lba;
+	iter->dos.cebr_siz = iter->dos.nebr_siz;
+
+	/* setup next frame values */
+	if (dp[1].ostype) {
+	    iter->dos.nebr_lba = iter->dos.bebr_lba + dp[1].start_lba;
+	    iter->dos.nebr_siz = dp[1].length;
+	} else {
+	    iter->dos.nebr_lba = 0;
+	    iter->dos.nebr_siz = 0;
+	}
+
+	if (!dp[0].ostype)
+	    iter->dos.logskipcnt++;
+
+	if (dp[0].ostype || (iter->flags & PIF_STEPALL)) {
+	    *lba = dp[0].start_lba ? iter->dos.cebr_lba + dp[0].start_lba : 0;
+	    *_dp = dp;
+	    return 0;
+	}
+	/*
+	 * This way it's possible to continue, if some crazy soft left a "hole"
+	 * - EBR with a valid extended partition without a logical one. In
+	 * such case, linux will not reserve a number for such hole - so we
+	 * don't increase index0. If PIF_STEPALL flag is set, we will never
+	 * reach this place.
+	 */
+    }
+    iter->status = PI_DONE;
+    return -1;
+}
+
+static void gpt_conv_label(struct part_iter *iter)
+{
+    const struct disk_gpt_part_entry *gp;
+    const int16_t *orig_lab;
+
+    gp = (const struct disk_gpt_part_entry *)
+	(iter->data + iter->index0 * iter->gpt.pe_size);
+    orig_lab = (const int16_t *)gp->name;
+
+    /* caveat: this is very crude conversion */
+    for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
+	iter->gpt.part_label[i] = (char)orig_lab[i];
+    }
+    iter->gpt.part_label[PI_GPTLABSIZE/2] = 0;
+}
+
+static int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz)
+{
+    return crc == crc32(crc32(0, NULL, 0), buf, siz);
+}
+
+static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh)
+{
+    struct disk_gpt_header *gh = *_gh;
+    uint64_t lba_alt;
+    uint32_t hold_crc32;
+
+    hold_crc32 = gh->chksum;
+    gh->chksum = 0;
+    if (!valid_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+	warn("Primary GPT header checksum invalid.");
+	/* retry with backup */
+	lba_alt = gh->lba_alt;
+	free(gh);
+	if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) {
+	    error("Couldn't read backup GPT header.");
+	    return -1;
+	}
+	hold_crc32 = gh->chksum;
+	gh->chksum = 0;
+	if (!valid_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+	    error("Secondary GPT header checksum invalid.");
+	    return -1;
+	}
+    }
+    /* restore old checksum */
+    gh->chksum = hold_crc32;
+
+    return 0;
+}
+
+static int pi_next_(struct part_iter *iter)
+{
+    iter->status = PI_DONE;
+    return iter->status;
+}
+
+static int pi_dos_next(struct part_iter *iter)
+{
+    uint32_t abs_lba = 0;
+    struct disk_dos_part_entry *dos_part = NULL;
+
+    if (iter->status)
+	return iter->status;
+
+    /* look for primary partitions */
+    if (iter->index0 < 4 &&
+	    dos_next_mbr(iter, &abs_lba, &dos_part) < 0)
+	return iter->status;
+
+    /* look for logical partitions */
+    if (iter->index0 >= 4 &&
+	    dos_next_ebr(iter, &abs_lba, &dos_part) < 0)
+	return iter->status;
+
+    /*
+     * note special index handling:
+     * in case PIF_STEPALL is set - this makes the index consistent with
+     * non-PIF_STEPALL iterators
+     */
+
+    if (!dos_part->ostype)
+	iter->index = -1;
+    else
+	iter->index = iter->index0 + 1 - iter->dos.logskipcnt;
+    iter->abs_lba = abs_lba;
+    iter->length = dos_part->length;
+    iter->record = (char *)dos_part;
+
+#ifdef DEBUG
+    disk_dos_part_dump(dos_part);
+#endif
+
+    return iter->status;
+}
+
+static int pi_gpt_next(struct part_iter *iter)
+{
+    const struct disk_gpt_part_entry *gpt_part = NULL;
+
+    if (iter->status)
+	return iter->status;
+
+    while (++iter->index0 < iter->gpt.pe_count) {
+	gpt_part = (const struct disk_gpt_part_entry *)
+	    (iter->data + iter->index0 * iter->gpt.pe_size);
+
+	if (notsane_gpt(iter)) {
+	    iter->status = PI_INSANE;
+	    return iter->status;
+	}
+
+	if (!guid_is0(&gpt_part->type) || (iter->flags & PIF_STEPALL))
+	    break;
+    }
+    /* no more partitions ? */
+    if (iter->index0 == iter->gpt.pe_count) {
+	iter->status = PI_DONE;
+	return iter->status;
+    }
+    /* gpt_part is guaranteed to be valid here */
+    iter->index = iter->index0 + 1;
+    iter->abs_lba = gpt_part->lba_first;
+    iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
+    iter->record = (char *)gpt_part;
+    memcpy(&iter->gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
+    gpt_conv_label(iter);
+
+#ifdef DEBUG
+    disk_gpt_part_dump(gpt_part);
+#endif
+
+    return iter->status;
+}
+
+static struct part_iter *pi_alloc(void)
+{
+    struct part_iter *iter;
+    if (!(iter = malloc(sizeof *iter)))
+	critm();
+    else
+	memset(iter, 0, sizeof *iter);
+    return iter;
+}
+
+/* pi_del() - delete iterator */
+void pi_del(struct part_iter **_iter)
+{
+    if(!_iter || !*_iter)
+	return;
+    pi_dtor(*_iter);
+    free(*_iter);
+    *_iter = NULL;
+}
+
+/* pi_begin() - validate and and get proper iterator for a disk described by di */
+struct part_iter *pi_begin(const struct disk_info *di, int flags)
+{
+    int gptprot, ret = -1;
+    struct part_iter *iter;
+    struct disk_dos_mbr *mbr = NULL;
+    struct disk_gpt_header *gpth = NULL;
+    struct disk_gpt_part_entry *gptl = NULL;
+
+    /* Preallocate iterator */
+    if (!(iter = pi_alloc()))
+	goto bail;
+
+    /* Read MBR */
+    if (!(mbr = disk_read_sectors(di, 0, 1))) {
+	error("Couldn't read the first disk sector.");
+	goto bail;
+    }
+
+    /* Check for MBR magic */
+    if (mbr->sig != disk_mbr_sig_magic) {
+	warn("No MBR magic, treating disk as raw.");
+	/* looks like RAW */
+	ret = pi_ctor(iter, di, flags);
+	goto bail;
+    }
+
+    /* Check for GPT protective MBR */
+    gptprot = 0;
+    for (size_t i = 0; i < 4; i++)
+	gptprot |= (mbr->table[i].ostype == 0xEE);
+    if (gptprot && !(flags & PIF_PREFMBR)) {
+	if (!(gpth = disk_read_sectors(di, 1, 1))) {
+	    error("Couldn't read potential GPT header.");
+	    goto bail;
+	}
+    }
+
+    if (gpth && gpth->rev.uint32 == 0x00010000 &&
+	    !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) {
+	/* looks like GPT v1.0 */
+	uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
+	uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
+	uint64_t gpt_lcnt;	    /* size of GPT partition in sectors */
+#ifdef DEBUG
+	dprintf("Looks like a GPT v1.0 disk.\n");
+	disk_gpt_header_dump(gpth);
+#endif
+	/* Verify checksum, fallback to backup, then bail if invalid */
+	if (gpt_check_hdr_crc(di, &gpth))
+	    goto bail;
+
+	gpt_loff = gpth->lba_table;
+	gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
+	gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
+
+	/*
+	 * disk_read_sectors allows reading of max 255 sectors, so we use
+	 * it as a sanity check base. EFI doesn't specify max (AFAIK).
+	 * Apart from that, some extensive sanity checks.
+	 */
+	if (!(flags & PIF_RELAX) && (
+		!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u ||
+		gpth->lba_first_usable > gpth->lba_last_usable ||
+		!sane(gpt_loff, gpt_lcnt) ||
+		gpt_loff + gpt_lcnt > gpth->lba_first_usable ||
+		!sane(gpth->lba_last_usable, gpt_lcnt) ||
+		gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt ||
+		gpth->lba_alt >= di->lbacnt ||
+		gpth->part_size < sizeof *gptl)) {
+	    error("Invalid GPT header's values.");
+	    goto bail;
+	}
+	if (!(gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt))) {
+	    error("Couldn't read GPT partition list.");
+	    goto bail;
+	}
+	/* Check array checksum(s). */
+	if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+	    warn("Checksum of the main GPT partition list is invalid, trying backup.");
+	    free(gptl);
+	    /* secondary array directly precedes secondary header */
+	    if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, gpt_lcnt))) {
+		error("Couldn't read backup GPT partition list.");
+		goto bail;
+	    }
+	    if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) {
+		error("Checksum of the backup GPT partition list is invalid, giving up.");
+		goto bail;
+	    }
+	}
+	/* looks like GPT */
+	ret = pi_gpt_ctor(iter, di, flags, gpth, gptl);
+    } else {
+	/* looks like MBR */
+	ret = pi_dos_ctor(iter, di, flags, mbr);
+    }
+bail:
+    if (ret < 0)
+	free(iter);
+    free(mbr);
+    free(gpth);
+    free(gptl);
+
+    return iter;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/lib/syslinux/utility.c b/com32/lib/syslinux/utility.c
new file mode 100644
index 0000000..e58df5e
--- /dev/null
+++ b/com32/lib/syslinux/utility.c
@@ -0,0 +1,256 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <com32.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <fs.h>
+#include <syslinux/disk.h>
+#include <syslinux/pmapi.h>
+#include <syslinux/utility.h>
+
+static const char *bpbtypes[] = {
+    [0] =  "unknown",
+    [1] =  "2.0",
+    [2] =  "3.0",
+    [3] =  "3.2",
+    [4] =  "3.4",
+    [5] =  "4.0",
+    [6] =  "8.0 (NT+)",
+    [7] =  "7.0",
+    [8] =  "exFAT",
+};
+
+void wait_key(void)
+{
+    int cnt;
+    char junk;
+
+    /* drain */
+    do {
+	errno = 0;
+	cnt = read(0, &junk, 1);
+    } while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
+
+    /* wait */
+    do {
+	errno = 0;
+	cnt = read(0, &junk, 1);
+    } while (!cnt || (cnt < 0 && errno == EAGAIN));
+}
+
+int guid_is0(const struct guid *guid)
+{
+    return
+	!(guid->data1 ||
+	  guid->data2 ||
+	  guid->data3 ||
+	  guid->data4);
+}
+
+/*
+ * mode explanation:
+ *
+ * cnul - "strict" mode, never returning higher value than obtained from cbios
+ * cadd - if the disk is larger than reported geometry /and/ if the geometry has
+ *        less cylinders than 1024 - it means that the total size is somewhere
+ *        between cs and cs+1; in this particular case, we bump the cs to be able
+ *        to return matching chs triplet
+ * cmax - assume we can use any cylinder value
+ *
+ * by default cadd seems most reasonable, giving consistent results with e.g.
+ * sfdisk's behavior
+ */
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode)
+{
+    uint32_t c, h, s, t;
+    uint32_t cs, hs, ss;
+
+    /*
+     * Not much reason here, but if we have no valid CHS geometry, we assume
+     * "typical" ones to have something to return.
+     */
+    if (di->cbios) {
+	cs = di->cyl;
+	hs = di->head;
+	ss = di->spt;
+	if (mode == L2C_CADD) {
+	    if (cs < 1024 && di->lbacnt > cs*hs*ss)
+		cs++;
+	} else if (mode == L2C_CMAX)
+	    cs = 1024;
+    } else {
+	if (di->disk & 0x80) {
+	    cs = 1024;
+	    hs = 255;
+	    ss = 63;
+	} else {
+	    cs = 80;
+	    hs = 2;
+	    ss = 18;
+	}
+    }
+
+    if (lba >= cs*hs*ss) {
+	s = ss;
+	h = hs - 1;
+	c = cs - 1;
+    } else {
+	s = (lba % ss) + 1;
+	t = lba / ss;
+	h = t % hs;
+	c = t / hs;
+    }
+
+    (*dst)[0] = h;
+    (*dst)[1] = s | ((c & 0x300) >> 2);
+    (*dst)[2] = c;
+}
+
+uint32_t get_file_lba(const char *filename)
+{
+    struct com32_filedata fd;
+    uint32_t lba = 0;
+    int size = 65536;
+    char *buf;
+
+    buf = lmalloc(size);
+    if (!buf)
+	return 0;
+
+    /* Put the filename in the bounce buffer */
+    strlcpy(buf, filename, size);
+
+    if (open_file(buf, O_RDONLY, &fd) <= 0) {
+	goto fail;		/* Filename not found */
+    }
+
+    /* Since the first member is the LBA, we simply cast */
+    lba = *((uint32_t *) MK_PTR(0, fd.handle));
+
+    /* Call comapi_close() to free the structure */
+    close_file(fd.handle);
+
+fail:
+    lfree(buf);
+    return lba;
+}
+
+/* drive offset detection */
+int drvoff_detect(int type)
+{
+    if (bpbV40 <= type && type <= bpbVNT) {
+	return 0x24;
+    } else if (type == bpbV70) {
+	return 0x40;
+    } else if (type == bpbEXF) {
+	return 0x6F;
+    }
+
+    return -1;
+}
+
+/*
+ * heuristics could certainly be improved
+ */
+int bpb_detect(const uint8_t *sec, const char *tag)
+{
+    int a, b, c, jmp = -1, rev = 0;
+
+    /* exFAT mess first (media descriptor is 0 here) */
+    if (!memcmp(sec + 0x03, "EXFAT   ", 8)) {
+	rev = bpbEXF;
+	goto out;
+    }
+
+    /* media descriptor check */
+    if ((sec[0x15] & 0xF0) != 0xF0)
+	goto out;
+
+    if (sec[0] == 0xEB)	/* jump short */
+	jmp = 2 + *(int8_t *)(sec + 1);
+    else if (sec[0] == 0xE9) /* jump near */
+	jmp = 3 + *(int16_t *)(sec + 1);
+
+    if (jmp < 0)    /* no boot code at all ? */
+	goto nocode;
+
+    /* sanity */
+    if (jmp < 0x18 || jmp > 0x1F0)
+	goto out;
+
+    /* detect by jump */
+    if (jmp >= 0x18 && jmp < 0x1E)
+	rev = bpbV20;
+    else if (jmp >= 0x1E && jmp < 0x20)
+	rev = bpbV30;
+    else if (jmp >= 0x20 && jmp < 0x24)
+	rev = bpbV32;
+    else if (jmp >= 0x24 && jmp < 0x46)
+	rev = bpbV34;
+
+    /* TODO: some better V2 - V3.4 checks ? */
+
+    if (rev)
+	goto out;
+    /*
+     * BPB info:
+     * 2.0 ==       0x0B - 0x17
+     * 3.0 == 2.0 + 0x18 - 0x1D
+     * 3.2 == 3.0 + 0x1E - 0x1F
+     * 3.4 ==!2.0 + 0x18 - 0x23
+     * 4.0 == 3.4 + 0x24 - 0x45
+     *  NT ==~3.4 + 0x24 - 0x53
+     * 7.0 == 3.4 + 0x24 - 0x59
+     */
+
+nocode:
+    a = memcmp(sec + 0x03, "NTFS", 4);
+    b = memcmp(sec + 0x36, "FAT", 3);
+    c = memcmp(sec + 0x52, "FAT", 3);	/* ext. DOS 7+ bs */
+
+    if ((sec[0x26] & 0xFE) == 0x28 && !b) {
+	rev = bpbV40;
+    } else if (sec[0x26] == 0x80 && !a) {
+	rev = bpbVNT;
+    } else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
+	rev = bpbV70;
+    }
+
+out:
+    printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]);
+    return rev;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/mk/lib.mk b/mk/lib.mk
index bc516c2..861daf8 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -106,7 +106,7 @@ LIBOTHER_OBJS = \
 	pci/writeb.o pci/writew.o pci/writel.o	\
 	\
 	sys/x86_init_fpu.o math/pow.o math/strtod.o			\
-	syslinux/disk.o							\
+	syslinux/disk.o	syslinux/utility.o syslinux/partiter.o		\
 	\
 	syslinux/setup_data.o
 
-- 
1.7.2.5



More information about the Syslinux mailing list