part_tbl.c 4.0 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 * linux/fs/hfsplus/part_tbl.c
L
Linus Torvalds 已提交
3 4
 *
 * Copyright (C) 1996-1997  Paul H. Hargrove
5 6
 * This file may be distributed under the terms of
 * the GNU General Public License.
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14 15 16
 *
 * Original code to handle the new style Mac partition table based on
 * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
 *
 * In function preconditions the term "valid" applied to a pointer to
 * a structure means that the pointer is non-NULL and the structure it
 * points to has all fields initialized to consistent values.
 *
 */

17
#include <linux/slab.h>
L
Linus Torvalds 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
#include "hfsplus_fs.h"

/* offsets to various blocks */
#define HFS_DD_BLK		0 /* Driver Descriptor block */
#define HFS_PMAP_BLK		1 /* First block of partition map */
#define HFS_MDB_BLK		2 /* Block (w/i partition) of MDB */

/* magic numbers for various disk blocks */
#define HFS_DRVR_DESC_MAGIC	0x4552 /* "ER": driver descriptor map */
#define HFS_OLD_PMAP_MAGIC	0x5453 /* "TS": old-type partition map */
#define HFS_NEW_PMAP_MAGIC	0x504D /* "PM": new-type partition map */
#define HFS_SUPER_MAGIC		0x4244 /* "BD": HFS MDB (super block) */
#define HFS_MFS_SUPER_MAGIC	0xD2D7 /* MFS MDB (super block) */

/*
 * The new style Mac partition map
 *
 * For each partition on the media there is a physical block (512-byte
 * block) containing one of these structures.  These blocks are
 * contiguous starting at block 1.
 */
struct new_pmap {
	__be16	pmSig;		/* signature */
	__be16	reSigPad;	/* padding */
	__be32	pmMapBlkCnt;	/* partition blocks count */
	__be32	pmPyPartStart;	/* physical block start of partition */
	__be32	pmPartBlkCnt;	/* physical block count of partition */
	u8	pmPartName[32];	/* (null terminated?) string
				   giving the name of this
				   partition */
	u8	pmPartType[32];	/* (null terminated?) string
				   giving the type of this
				   partition */
	/* a bunch more stuff we don't need */
} __packed;

/*
 * The old style Mac partition map
 *
 * The partition map consists for a 2-byte signature followed by an
 * array of these structures.  The map is terminated with an all-zero
 * one of these.
 */
struct old_pmap {
	__be16		pdSig;	/* Signature bytes */
63
	struct old_pmap_entry {
L
Linus Torvalds 已提交
64 65 66 67 68 69
		__be32	pdStart;
		__be32	pdSize;
		__be32	pdFSID;
	}	pdEntry[42];
} __packed;

70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
		sector_t *part_start, sector_t *part_size)
{
	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
	int i;

	for (i = 0; i < 42; i++) {
		struct old_pmap_entry *p = &pm->pdEntry[i];

		if (p->pdStart && p->pdSize &&
		    p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
		    (sbi->part < 0 || sbi->part == i)) {
			*part_start += be32_to_cpu(p->pdStart);
			*part_size = be32_to_cpu(p->pdSize);
			return 0;
		}
	}

	return -ENOENT;
}

static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm,
		sector_t *part_start, sector_t *part_size)
{
	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
	int size = be32_to_cpu(pm->pmMapBlkCnt);
	int res;
	int i = 0;

	do {
100
		if (!memcmp(pm->pmPartType, "Apple_HFS", 9) &&
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
		    (sbi->part < 0 || sbi->part == i)) {
			*part_start += be32_to_cpu(pm->pmPyPartStart);
			*part_size = be32_to_cpu(pm->pmPartBlkCnt);
			return 0;
		}

		if (++i >= size)
			return -ENOENT;

		res = hfsplus_submit_bio(sb->s_bdev,
					 *part_start + HFS_PMAP_BLK + i,
					 pm, READ);
		if (res)
			return res;
	} while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));

	return -ENOENT;
}

L
Linus Torvalds 已提交
120
/*
121 122
 * Parse the partition map looking for the start and length of a
 * HFS/HFS+ partition.
L
Linus Torvalds 已提交
123 124
 */
int hfs_part_find(struct super_block *sb,
125
		sector_t *part_start, sector_t *part_size)
L
Linus Torvalds 已提交
126
{
127 128 129 130 131 132
	void *data;
	int res;

	data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL);
	if (!data)
		return -ENOMEM;
L
Linus Torvalds 已提交
133

134 135 136
	res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK,
				 data, READ);
	if (res)
137
		goto out;
L
Linus Torvalds 已提交
138

139
	switch (be16_to_cpu(*((__be16 *)data))) {
L
Linus Torvalds 已提交
140
	case HFS_OLD_PMAP_MAGIC:
141
		res = hfs_parse_old_pmap(sb, data, part_start, part_size);
L
Linus Torvalds 已提交
142 143
		break;
	case HFS_NEW_PMAP_MAGIC:
144 145 146 147
		res = hfs_parse_new_pmap(sb, data, part_start, part_size);
		break;
	default:
		res = -ENOENT;
L
Linus Torvalds 已提交
148 149
		break;
	}
150
out:
151
	kfree(data);
L
Linus Torvalds 已提交
152 153
	return res;
}