Beispiel #1
0
static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
		uint32_t ex_start, uint32_t ex_size, int ssf)
{
	blkid_partlist ls = blkid_probe_get_partlist(pr);
	uint32_t cur_start = ex_start, cur_size = ex_size;
	unsigned char *data;
	int ct_nodata = 0;	/* count ext.partitions without data partitions */
	int i;

	DBG(LOWPROBE, ul_debug("parse EBR [start=%d, size=%d]", ex_start/ssf, ex_size/ssf));
	if (ex_start == 0) {
		DBG(LOWPROBE, ul_debug("Bad offset in primary extended partition -- ignore"));
		return 0;
	}

	while (1) {
		struct dos_partition *p, *p0;
		uint32_t start, size;

		if (++ct_nodata > 100)
			return BLKID_PROBE_OK;
		data = blkid_probe_get_sector(pr, cur_start);
		if (!data) {
			if (errno)
				return -errno;
			goto leave;	/* malformed partition? */
		}

		if (!mbr_is_valid_magic(data))
			goto leave;

		p0 = mbr_get_partition(data, 0);

		/* Usually, the first entry is the real data partition,
		 * the 2nd entry is the next extended partition, or empty,
		 * and the 3rd and 4th entries are unused.
		 * However, DRDOS sometimes has the extended partition as
		 * the first entry (when the data partition is empty),
		 * and OS/2 seems to use all four entries.
		 * -- Linux kernel fs/partitions/dos.c
		 *
		 * See also http://en.wikipedia.org/wiki/Extended_boot_record
		 */

		/* Parse data partition */
		for (p = p0, i = 0; i < 4; i++, p++) {
			uint32_t abs_start;
			blkid_partition par;

			/* the start is relative to the parental ext.partition */
			start = dos_partition_get_start(p) * ssf;
			size = dos_partition_get_size(p) * ssf;
			abs_start = cur_start + start;	/* absolute start */

			if (!size || is_extended(p))
				continue;
			if (i >= 2) {
				/* extra checks to detect real data on
				 * 3rd and 4th entries */
				if (start + size > cur_size)
					continue;
				if (abs_start < ex_start)
					continue;
				if (abs_start + size > ex_start + ex_size)
					continue;
			}

			/* Avoid recursive non-empty links, see ct_nodata counter */
			if (blkid_partlist_get_partition_by_start(ls, abs_start)) {
				DBG(LOWPROBE, ul_debug("#%d: EBR duplicate data partition [abs start=%u] -- ignore",
							i + 1, abs_start));
				continue;
			}

			par = blkid_partlist_add_partition(ls, tab, abs_start, size);
			if (!par)
				return -ENOMEM;

			blkid_partition_set_type(par, p->sys_ind);
			blkid_partition_set_flags(par, p->boot_ind);
			blkid_partition_gen_uuid(par);
			ct_nodata = 0;
		}
		/* The first nested ext.partition should be a link to the next
		 * logical partition. Everything other (recursive ext.partitions)
		 * is junk.
		 */
		for (p = p0, i = 0; i < 4; i++, p++) {
			start = dos_partition_get_start(p) * ssf;
			size = dos_partition_get_size(p) * ssf;

			if (size && is_extended(p)) {
				if (start == 0)
					DBG(LOWPROBE, ul_debug("#%d: EBR link offset is zero -- ignore", i + 1));
				else
					break;
			}
		}
		if (i == 4)
			goto leave;

		cur_start = ex_start + start;
		cur_size = size;
	}
leave:
	return BLKID_PROBE_OK;
}
Beispiel #2
0
static int parse_dos_extended(blkid_probe pr, blkid_parttable tab,
		uint32_t ex_start, uint32_t ex_size, int ssf)
{
	blkid_partlist ls = blkid_probe_get_partlist(pr);
	uint32_t cur_start = ex_start, cur_size = ex_size;
	unsigned char *data;
	int ct_nodata = 0;	/* count ext.partitions without data partitions */
	int i;

	while (1) {
		struct dos_partition *p, *p0;
		uint32_t start, size;

		if (++ct_nodata > 100)
			return 0;
		data = blkid_probe_get_sector(pr, cur_start);
		if (!data)
			goto leave;	/* malformed partition? */

		if (!is_valid_mbr_signature(data))
			goto leave;

		p0 = (struct dos_partition *) (data + BLKID_MSDOS_PT_OFFSET);

		/* Usually, the first entry is the real data partition,
		 * the 2nd entry is the next extended partition, or empty,
		 * and the 3rd and 4th entries are unused.
		 * However, DRDOS sometimes has the extended partition as
		 * the first entry (when the data partition is empty),
		 * and OS/2 seems to use all four entries.
		 * -- Linux kernel fs/partitions/dos.c
		 *
		 * See also http://en.wikipedia.org/wiki/Extended_boot_record
		 */

		/* Parse data partition */
		for (p = p0, i = 0; i < 4; i++, p++) {
			uint32_t abs_start;
			blkid_partition par;

			/* the start is relative to the parental ext.partition */
			start = dos_partition_start(p) * ssf;
			size = dos_partition_size(p) * ssf;
			abs_start = cur_start + start;	/* absolute start */

			if (!size || is_extended(p))
				continue;
			if (i >= 2) {
				/* extra checks to detect real data on
				 * 3rd and 4th entries */
				if (start + size > cur_size)
					continue;
				if (abs_start < ex_start)
					continue;
				if (abs_start + size > ex_start + ex_size)
					continue;
			}

			par = blkid_partlist_add_partition(ls, tab, abs_start, size);
			if (!par)
				goto err;

			blkid_partition_set_type(par, p->sys_type);
			blkid_partition_set_flags(par, p->boot_ind);
			ct_nodata = 0;
		}
		/* The first nested ext.partition should be a link to the next
		 * logical partition. Everything other (recursive ext.partitions)
		 * is junk.
		 */
		for (p = p0, i = 0; i < 4; i++, p++) {
			start = dos_partition_start(p) * ssf;
			size = dos_partition_size(p) * ssf;

			if (size && is_extended(p))
				break;
		}
		if (i == 4)
			goto leave;

		cur_start = ex_start + start;
		cur_size = size;
	}
leave:
	return 0;
err:
	return -1;
}
Beispiel #3
0
static int probe_bsd_pt(blkid_probe pr, const struct blkid_idmag *mag)
{
	struct bsd_disklabel *l;
	struct bsd_partition *p;
	const char *name = "bsd" ;
	blkid_parttable tab = NULL;
	blkid_partition parent;
	blkid_partlist ls;
	int i, nparts = BSD_MAXPARTITIONS;
	unsigned char *data;
	int rc = BLKID_PROBE_NONE;

	if (blkid_partitions_need_typeonly(pr))
		/* caller does not ask for details about partitions */
		return rc;

	data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag));
	if (!data) {
		if (errno)
			rc = -errno;
		goto nothing;
	}

	l = (struct bsd_disklabel *) data + BLKID_MAG_LASTOFFSET(mag);

	ls = blkid_probe_get_partlist(pr);
	if (!ls)
		goto nothing;

	/* try to determine the real type of BSD system according to
	 * (parental) primary partition */
	parent = blkid_partlist_get_parent(ls);
	if (parent) {
		switch(blkid_partition_get_type(parent)) {
		case MBR_FREEBSD_PARTITION:
			name = "freebsd";
			break;
		case MBR_NETBSD_PARTITION:
			name = "netbsd";
			break;
		case MBR_OPENBSD_PARTITION:
			name = "openbsd";
			break;
		default:
			DBG(LOWPROBE, ul_debug(
				"WARNING: BSD label detected on unknown (0x%x) "
				"primary partition",
				blkid_partition_get_type(parent)));
			break;
		}
	}

	tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag));
	if (!tab) {
		rc = -ENOMEM;
		goto nothing;
	}

	if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS)
		nparts = le16_to_cpu(l->d_npartitions);

	else if (le16_to_cpu(l->d_npartitions) > BSD_MAXPARTITIONS)
		DBG(LOWPROBE, ul_debug(
			"WARNING: ignore %d more BSD partitions",
			le16_to_cpu(l->d_npartitions) - BSD_MAXPARTITIONS));

	for (i = 0, p = l->d_partitions; i < nparts; i++, p++) {
		blkid_partition par;
		uint32_t start, size;

		/* TODO: in fdisk-mode returns all non-zero (p_size) partitions */
		if (p->p_fstype == BSD_FS_UNUSED)
			continue;

		start = le32_to_cpu(p->p_offset);
		size = le32_to_cpu(p->p_size);

		if (parent && blkid_partition_get_start(parent) == start
			   && blkid_partition_get_size(parent) == size) {
			DBG(LOWPROBE, ul_debug(
				"WARNING: BSD partition (%d) same like parent, "
				"ignore", i));
			continue;
		}
		if (parent && !blkid_is_nested_dimension(parent, start, size)) {
			DBG(LOWPROBE, ul_debug(
				"WARNING: BSD partition (%d) overflow "
				"detected, ignore", i));
			continue;
		}

		par = blkid_partlist_add_partition(ls, tab, start, size);
		if (!par) {
			rc = -ENOMEM;
			goto nothing;
		}

		blkid_partition_set_type(par, p->p_fstype);
	}

	return BLKID_PROBE_OK;

nothing:
	return rc;
}