162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  linux/fs/hfs/part_tbl.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 1996-1997  Paul H. Hargrove
562306a36Sopenharmony_ci * (C) 2003 Ardis Technologies <roman@ardistech.com>
662306a36Sopenharmony_ci * This file may be distributed under the terms of the GNU General Public License.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Original code to handle the new style Mac partition table based on
962306a36Sopenharmony_ci * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "hfs_fs.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * The new style Mac partition map
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * For each partition on the media there is a physical block (512-byte
1862306a36Sopenharmony_ci * block) containing one of these structures.  These blocks are
1962306a36Sopenharmony_ci * contiguous starting at block 1.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_cistruct new_pmap {
2262306a36Sopenharmony_ci	__be16	pmSig;		/* signature */
2362306a36Sopenharmony_ci	__be16	reSigPad;	/* padding */
2462306a36Sopenharmony_ci	__be32	pmMapBlkCnt;	/* partition blocks count */
2562306a36Sopenharmony_ci	__be32	pmPyPartStart;	/* physical block start of partition */
2662306a36Sopenharmony_ci	__be32	pmPartBlkCnt;	/* physical block count of partition */
2762306a36Sopenharmony_ci	u8	pmPartName[32];	/* (null terminated?) string
2862306a36Sopenharmony_ci				   giving the name of this
2962306a36Sopenharmony_ci				   partition */
3062306a36Sopenharmony_ci	u8	pmPartType[32];	/* (null terminated?) string
3162306a36Sopenharmony_ci				   giving the type of this
3262306a36Sopenharmony_ci				   partition */
3362306a36Sopenharmony_ci	/* a bunch more stuff we don't need */
3462306a36Sopenharmony_ci} __packed;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * The old style Mac partition map
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * The partition map consists for a 2-byte signature followed by an
4062306a36Sopenharmony_ci * array of these structures.  The map is terminated with an all-zero
4162306a36Sopenharmony_ci * one of these.
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_cistruct old_pmap {
4462306a36Sopenharmony_ci	__be16		pdSig;	/* Signature bytes */
4562306a36Sopenharmony_ci	struct 	old_pmap_entry {
4662306a36Sopenharmony_ci		__be32	pdStart;
4762306a36Sopenharmony_ci		__be32	pdSize;
4862306a36Sopenharmony_ci		__be32	pdFSID;
4962306a36Sopenharmony_ci	}	pdEntry[42];
5062306a36Sopenharmony_ci} __packed;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/*
5362306a36Sopenharmony_ci * hfs_part_find()
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * Parse the partition map looking for the
5662306a36Sopenharmony_ci * start and length of the 'part'th HFS partition.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ciint hfs_part_find(struct super_block *sb,
5962306a36Sopenharmony_ci		  sector_t *part_start, sector_t *part_size)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct buffer_head *bh;
6262306a36Sopenharmony_ci	__be16 *data;
6362306a36Sopenharmony_ci	int i, size, res;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	res = -ENOENT;
6662306a36Sopenharmony_ci	bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data);
6762306a36Sopenharmony_ci	if (!bh)
6862306a36Sopenharmony_ci		return -EIO;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	switch (be16_to_cpu(*data)) {
7162306a36Sopenharmony_ci	case HFS_OLD_PMAP_MAGIC:
7262306a36Sopenharmony_ci	  {
7362306a36Sopenharmony_ci		struct old_pmap *pm;
7462306a36Sopenharmony_ci		struct old_pmap_entry *p;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci		pm = (struct old_pmap *)bh->b_data;
7762306a36Sopenharmony_ci		p = pm->pdEntry;
7862306a36Sopenharmony_ci		size = 42;
7962306a36Sopenharmony_ci		for (i = 0; i < size; p++, i++) {
8062306a36Sopenharmony_ci			if (p->pdStart && p->pdSize &&
8162306a36Sopenharmony_ci			    p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
8262306a36Sopenharmony_ci			    (HFS_SB(sb)->part < 0 || HFS_SB(sb)->part == i)) {
8362306a36Sopenharmony_ci				*part_start += be32_to_cpu(p->pdStart);
8462306a36Sopenharmony_ci				*part_size = be32_to_cpu(p->pdSize);
8562306a36Sopenharmony_ci				res = 0;
8662306a36Sopenharmony_ci			}
8762306a36Sopenharmony_ci		}
8862306a36Sopenharmony_ci		break;
8962306a36Sopenharmony_ci	  }
9062306a36Sopenharmony_ci	case HFS_NEW_PMAP_MAGIC:
9162306a36Sopenharmony_ci	  {
9262306a36Sopenharmony_ci		struct new_pmap *pm;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		pm = (struct new_pmap *)bh->b_data;
9562306a36Sopenharmony_ci		size = be32_to_cpu(pm->pmMapBlkCnt);
9662306a36Sopenharmony_ci		for (i = 0; i < size;) {
9762306a36Sopenharmony_ci			if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
9862306a36Sopenharmony_ci			    (HFS_SB(sb)->part < 0 || HFS_SB(sb)->part == i)) {
9962306a36Sopenharmony_ci				*part_start += be32_to_cpu(pm->pmPyPartStart);
10062306a36Sopenharmony_ci				*part_size = be32_to_cpu(pm->pmPartBlkCnt);
10162306a36Sopenharmony_ci				res = 0;
10262306a36Sopenharmony_ci				break;
10362306a36Sopenharmony_ci			}
10462306a36Sopenharmony_ci			brelse(bh);
10562306a36Sopenharmony_ci			bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm);
10662306a36Sopenharmony_ci			if (!bh)
10762306a36Sopenharmony_ci				return -EIO;
10862306a36Sopenharmony_ci			if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC))
10962306a36Sopenharmony_ci				break;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci		break;
11262306a36Sopenharmony_ci	  }
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci	brelse(bh);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return res;
11762306a36Sopenharmony_ci}
118