Exemple #1
0
static void extended_partition(struct gendisk *hd, struct block_device *bdev,
			int minor, unsigned long first_size, int *current_minor)
{
	struct partition *p;
	Sector sect;
	unsigned char *data;
	unsigned long first_sector, this_sector, this_size;
	int mask = (1 << hd->minor_shift) - 1;
	int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
	int loopct = 0;		/* number of links followed
				   without finding a data partition */
	int i;

	this_sector = first_sector = hd->part[minor].start_sect;
	this_size = first_size;

	while (1) {
		if (++loopct > 100)
			return;
		if ((*current_minor & mask) == 0)
			return;
		data = read_dev_sector(bdev, this_sector, &sect);
		if (!data)
			return;

		if (!msdos_magic_present(data + 510))
			goto done; 

		p = (struct partition *) (data + 0x1be);

		/*
		 * 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.
		 */

		/* 
		 * First process the data partition(s)
		 */
		for (i=0; i<4; i++, p++) {
			unsigned long offs, size, next;
			if (!NR_SECTS(p) || is_extended_partition(p))
				continue;

			/* Check the 3rd and 4th entries -
			   these sometimes contain random garbage */
			offs = START_SECT(p)*sector_size;
			size = NR_SECTS(p)*sector_size;
			next = this_sector + offs;
			if (i >= 2) {
				if (offs + size > this_size)
					continue;
				if (next < first_sector)
					continue;
				if (next + size > first_sector + first_size)
					continue;
			}

			add_gd_partition(hd, *current_minor, next, size);
#if CONFIG_BLK_DEV_MD
			if (SYS_IND(p) == LINUX_RAID_PARTITION) {
			    md_autodetect_dev(MKDEV(hd->major,*current_minor));
			}
#endif

			(*current_minor)++;
			loopct = 0;
			if ((*current_minor & mask) == 0)
				goto done;
		}
		/*
		 * Next, process the (first) extended partition, if present.
		 * (So far, there seems to be no reason to make
		 *  extended_partition()  recursive and allow a tree
		 *  of extended partitions.)
		 * It should be a link to the next logical partition.
		 * Create a minor for this just long enough to get the next
		 * partition table.  The minor will be reused for the next
		 * data partition.
		 */
		p -= 4;
		for (i=0; i<4; i++, p++)
			if (NR_SECTS(p) && is_extended_partition(p))
				break;
		if (i == 4)
			goto done;	 /* nothing left to do */

		this_sector = first_sector + START_SECT(p) * sector_size;
		this_size = NR_SECTS(p) * sector_size;
		minor = *current_minor;
		put_dev_sector(sect);
	}
done:
	put_dev_sector(sect);
}
Exemple #2
0
int msdos_partition(struct gendisk *hd, struct block_device *bdev,
		    unsigned long first_sector, int first_part_minor)
{
	int i, minor = first_part_minor;
	Sector sect;
	struct partition *p;
	unsigned char *data;
	int mask = (1 << hd->minor_shift) - 1;
	int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
	int current_minor = first_part_minor;
	int err;

	err = handle_ide_mess(bdev);
	if (err <= 0)
		return err;
	data = read_dev_sector(bdev, 0, &sect);
	if (!data)
		return -1;
	if (!msdos_magic_present(data + 510)) {
		put_dev_sector(sect);
		return 0;
	}
	p = (struct partition *) (data + 0x1be);

	/*
	 * Look for partitions in two passes:
	 * First find the primary and DOS-type extended partitions.
	 * On the second pass look inside *BSD, Unixware and Solaris partitions.
	 */

	current_minor += 4;
	for (i=1 ; i<=4 ; minor++,i++,p++) {
		if (!NR_SECTS(p))
			continue;
		add_gd_partition(hd, minor,
				first_sector+START_SECT(p)*sector_size,
				NR_SECTS(p)*sector_size);
#if CONFIG_BLK_DEV_MD
		if (SYS_IND(p) == LINUX_RAID_PARTITION) {
			md_autodetect_dev(MKDEV(hd->major,minor));
		}
#endif
		if (is_extended_partition(p)) {
			unsigned long size = hd->part[minor].nr_sects;
			printk(" <");
			/* prevent someone doing mkfs or mkswap on an
			   extended partition, but leave room for LILO */
			if (size > 2)
				hd->part[minor].nr_sects = 2;
			extended_partition(hd, bdev, minor, size, &current_minor);
			printk(" >");
		}
	}

	/*
	 *  Check for old-style Disk Manager partition table
	 */
	if (msdos_magic_present(data + 0xfc)) {
		p = (struct partition *) (0x1be + data);
		for (i = 4 ; i < 16 ; i++, current_minor++) {
			p--;
			if ((current_minor & mask) == 0)
				break;
			if (!(START_SECT(p) && NR_SECTS(p)))
				continue;
			add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
		}
	}
	printk("\n");

	/* second pass - output for each on a separate line */
	minor -= 4;
	p = (struct partition *) (0x1be + data);
	for (i=1 ; i<=4 ; minor++,i++,p++) {
		unsigned char id = SYS_IND(p);
		int n;

		if (!NR_SECTS(p))
			continue;

		for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
			;

		if (subtypes[n].parse)
			subtypes[n].parse(hd, bdev, minor, &current_minor);
	}
	put_dev_sector(sect);
	return 1;
}
Exemple #3
0
int msdos_partition(struct gendisk *hd, struct block_device *bdev,
		    unsigned long first_sector, int first_part_minor)
{
	int i, minor = first_part_minor;
	Sector sect;
	struct partition *p;
	unsigned char *data;
	int mask = (1 << hd->minor_shift) - 1;
	int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
	int current_minor = first_part_minor;
	int err;
#ifdef CONFIG_IDE_IPOD
	int sector_mult = 1;
#endif

	err = handle_ide_mess(bdev);
	if (err <= 0)
		return err;
	data = read_dev_sector(bdev, 0, &sect);
	if (!data)
		return -1;
	if (!msdos_magic_present(data + 510)) {
		put_dev_sector(sect);
		return 0;
	}
	p = (struct partition *) (data + 0x1be);

#ifdef CONFIG_IDE_IPOD
	/*
	 * Addition for iPods: check for actual filesystems to figure out the correct partition layout
	 */
	for (i=1 ; i<=4 ; i++,p++) {
		unsigned char *partdata;

		if (!NR_SECTS(p))
			continue;
		if (SYS_IND(p) == 0xb) {
			partdata = read_dev_sector(bdev, first_sector+START_SECT(p)*sector_size*4, &sect);
			if (msdos_magic_present(partdata + 510))
				sector_mult = 4;

			partdata = read_dev_sector(bdev, first_sector+START_SECT(p)*sector_size*2, &sect);
			if (msdos_magic_present(partdata + 510))
				sector_mult = 2;

			partdata = read_dev_sector(bdev, first_sector+START_SECT(p)*sector_size, &sect);
			if (msdos_magic_present(partdata + 510))
				sector_mult = 1;
        
		} else if (SYS_IND(p) == 0x83) {
			partdata = read_dev_sector(bdev, first_sector+START_SECT(p)*sector_size*4+2, &sect);
			if (ext3_magic_present(partdata + 56))
				sector_mult = 4;

			partdata = read_dev_sector(bdev, first_sector+START_SECT(p)*sector_size*2+2, &sect);
			if (ext3_magic_present(partdata + 56))
				sector_mult = 2;

			partdata = read_dev_sector(bdev, first_sector+START_SECT(p)*sector_size+2, &sect);
			if (ext3_magic_present(partdata + 56))
				sector_mult = 1;
		}
	}

	printk("Experimental partition and filesystem detection code by Vincent Huisman ([email protected])\n"); 
	printk("Partition sector size: %d\n", sector_mult);

	sector_size *= sector_mult;
	p = (struct partition *) (data + 0x1be); // Reinitialize, duh
#endif

	/*
	 * Look for partitions in two passes:
	 * First find the primary and DOS-type extended partitions.
	 * On the second pass look inside *BSD, Unixware and Solaris partitions.
	 */

	current_minor += 4;
	for (i=1 ; i<=4 ; minor++,i++,p++) {
		if (!NR_SECTS(p))
			continue;
		add_gd_partition(hd, minor,
				first_sector+START_SECT(p)*sector_size,
				NR_SECTS(p)*sector_size);
#if CONFIG_BLK_DEV_MD
		if (SYS_IND(p) == LINUX_RAID_PARTITION) {
			md_autodetect_dev(MKDEV(hd->major,minor));
		}
#endif
		if (is_extended_partition(p)) {
			unsigned long size = hd->part[minor].nr_sects;
			printk(" <");
			/* prevent someone doing mkfs or mkswap on an
			   extended partition, but leave room for LILO */
			if (size > 2)
				hd->part[minor].nr_sects = 2;
			extended_partition(hd, bdev, minor, size, &current_minor);
			printk(" >");
		}
	}

	/*
	 *  Check for old-style Disk Manager partition table
	 */
	if (msdos_magic_present(data + 0xfc)) {
		p = (struct partition *) (0x1be + data);
		for (i = 4 ; i < 16 ; i++, current_minor++) {
			p--;
			if ((current_minor & mask) == 0)
				break;
			if (!(START_SECT(p) && NR_SECTS(p)))
				continue;
			add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
		}
	}
	printk("\n");

	/* second pass - output for each on a separate line */
	minor -= 4;
	p = (struct partition *) (0x1be + data);
	for (i=1 ; i<=4 ; minor++,i++,p++) {
		unsigned char id = SYS_IND(p);
		int n;

		if (!NR_SECTS(p))
			continue;

		for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
			;

		if (subtypes[n].parse)
			subtypes[n].parse(hd, bdev, minor, &current_minor);
	}
	put_dev_sector(sect);
	return 1;
}