xref: /OK3568_Linux_fs/kernel/fs/hfsplus/part_tbl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * linux/fs/hfsplus/part_tbl.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 1996-1997  Paul H. Hargrove
5*4882a593Smuzhiyun  * This file may be distributed under the terms of
6*4882a593Smuzhiyun  * the GNU General Public License.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Original code to handle the new style Mac partition table based on
9*4882a593Smuzhiyun  * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * In function preconditions the term "valid" applied to a pointer to
12*4882a593Smuzhiyun  * a structure means that the pointer is non-NULL and the structure it
13*4882a593Smuzhiyun  * points to has all fields initialized to consistent values.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include "hfsplus_fs.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* offsets to various blocks */
21*4882a593Smuzhiyun #define HFS_DD_BLK		0 /* Driver Descriptor block */
22*4882a593Smuzhiyun #define HFS_PMAP_BLK		1 /* First block of partition map */
23*4882a593Smuzhiyun #define HFS_MDB_BLK		2 /* Block (w/i partition) of MDB */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* magic numbers for various disk blocks */
26*4882a593Smuzhiyun #define HFS_DRVR_DESC_MAGIC	0x4552 /* "ER": driver descriptor map */
27*4882a593Smuzhiyun #define HFS_OLD_PMAP_MAGIC	0x5453 /* "TS": old-type partition map */
28*4882a593Smuzhiyun #define HFS_NEW_PMAP_MAGIC	0x504D /* "PM": new-type partition map */
29*4882a593Smuzhiyun #define HFS_SUPER_MAGIC		0x4244 /* "BD": HFS MDB (super block) */
30*4882a593Smuzhiyun #define HFS_MFS_SUPER_MAGIC	0xD2D7 /* MFS MDB (super block) */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * The new style Mac partition map
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * For each partition on the media there is a physical block (512-byte
36*4882a593Smuzhiyun  * block) containing one of these structures.  These blocks are
37*4882a593Smuzhiyun  * contiguous starting at block 1.
38*4882a593Smuzhiyun  */
39*4882a593Smuzhiyun struct new_pmap {
40*4882a593Smuzhiyun 	__be16	pmSig;		/* signature */
41*4882a593Smuzhiyun 	__be16	reSigPad;	/* padding */
42*4882a593Smuzhiyun 	__be32	pmMapBlkCnt;	/* partition blocks count */
43*4882a593Smuzhiyun 	__be32	pmPyPartStart;	/* physical block start of partition */
44*4882a593Smuzhiyun 	__be32	pmPartBlkCnt;	/* physical block count of partition */
45*4882a593Smuzhiyun 	u8	pmPartName[32];	/* (null terminated?) string
46*4882a593Smuzhiyun 				   giving the name of this
47*4882a593Smuzhiyun 				   partition */
48*4882a593Smuzhiyun 	u8	pmPartType[32];	/* (null terminated?) string
49*4882a593Smuzhiyun 				   giving the type of this
50*4882a593Smuzhiyun 				   partition */
51*4882a593Smuzhiyun 	/* a bunch more stuff we don't need */
52*4882a593Smuzhiyun } __packed;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /*
55*4882a593Smuzhiyun  * The old style Mac partition map
56*4882a593Smuzhiyun  *
57*4882a593Smuzhiyun  * The partition map consists for a 2-byte signature followed by an
58*4882a593Smuzhiyun  * array of these structures.  The map is terminated with an all-zero
59*4882a593Smuzhiyun  * one of these.
60*4882a593Smuzhiyun  */
61*4882a593Smuzhiyun struct old_pmap {
62*4882a593Smuzhiyun 	__be16		pdSig;	/* Signature bytes */
63*4882a593Smuzhiyun 	struct old_pmap_entry {
64*4882a593Smuzhiyun 		__be32	pdStart;
65*4882a593Smuzhiyun 		__be32	pdSize;
66*4882a593Smuzhiyun 		__be32	pdFSID;
67*4882a593Smuzhiyun 	}	pdEntry[42];
68*4882a593Smuzhiyun } __packed;
69*4882a593Smuzhiyun 
hfs_parse_old_pmap(struct super_block * sb,struct old_pmap * pm,sector_t * part_start,sector_t * part_size)70*4882a593Smuzhiyun static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
71*4882a593Smuzhiyun 		sector_t *part_start, sector_t *part_size)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
74*4882a593Smuzhiyun 	int i;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	for (i = 0; i < 42; i++) {
77*4882a593Smuzhiyun 		struct old_pmap_entry *p = &pm->pdEntry[i];
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		if (p->pdStart && p->pdSize &&
80*4882a593Smuzhiyun 		    p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
81*4882a593Smuzhiyun 		    (sbi->part < 0 || sbi->part == i)) {
82*4882a593Smuzhiyun 			*part_start += be32_to_cpu(p->pdStart);
83*4882a593Smuzhiyun 			*part_size = be32_to_cpu(p->pdSize);
84*4882a593Smuzhiyun 			return 0;
85*4882a593Smuzhiyun 		}
86*4882a593Smuzhiyun 	}
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	return -ENOENT;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
hfs_parse_new_pmap(struct super_block * sb,void * buf,struct new_pmap * pm,sector_t * part_start,sector_t * part_size)91*4882a593Smuzhiyun static int hfs_parse_new_pmap(struct super_block *sb, void *buf,
92*4882a593Smuzhiyun 		struct new_pmap *pm, sector_t *part_start, sector_t *part_size)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
95*4882a593Smuzhiyun 	int size = be32_to_cpu(pm->pmMapBlkCnt);
96*4882a593Smuzhiyun 	int buf_size = hfsplus_min_io_size(sb);
97*4882a593Smuzhiyun 	int res;
98*4882a593Smuzhiyun 	int i = 0;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	do {
101*4882a593Smuzhiyun 		if (!memcmp(pm->pmPartType, "Apple_HFS", 9) &&
102*4882a593Smuzhiyun 		    (sbi->part < 0 || sbi->part == i)) {
103*4882a593Smuzhiyun 			*part_start += be32_to_cpu(pm->pmPyPartStart);
104*4882a593Smuzhiyun 			*part_size = be32_to_cpu(pm->pmPartBlkCnt);
105*4882a593Smuzhiyun 			return 0;
106*4882a593Smuzhiyun 		}
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 		if (++i >= size)
109*4882a593Smuzhiyun 			return -ENOENT;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 		pm = (struct new_pmap *)((u8 *)pm + HFSPLUS_SECTOR_SIZE);
112*4882a593Smuzhiyun 		if ((u8 *)pm - (u8 *)buf >= buf_size) {
113*4882a593Smuzhiyun 			res = hfsplus_submit_bio(sb,
114*4882a593Smuzhiyun 						 *part_start + HFS_PMAP_BLK + i,
115*4882a593Smuzhiyun 						 buf, (void **)&pm, REQ_OP_READ,
116*4882a593Smuzhiyun 						 0);
117*4882a593Smuzhiyun 			if (res)
118*4882a593Smuzhiyun 				return res;
119*4882a593Smuzhiyun 		}
120*4882a593Smuzhiyun 	} while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return -ENOENT;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun  * Parse the partition map looking for the start and length of a
127*4882a593Smuzhiyun  * HFS/HFS+ partition.
128*4882a593Smuzhiyun  */
hfs_part_find(struct super_block * sb,sector_t * part_start,sector_t * part_size)129*4882a593Smuzhiyun int hfs_part_find(struct super_block *sb,
130*4882a593Smuzhiyun 		sector_t *part_start, sector_t *part_size)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	void *buf, *data;
133*4882a593Smuzhiyun 	int res;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
136*4882a593Smuzhiyun 	if (!buf)
137*4882a593Smuzhiyun 		return -ENOMEM;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	res = hfsplus_submit_bio(sb, *part_start + HFS_PMAP_BLK,
140*4882a593Smuzhiyun 				 buf, &data, REQ_OP_READ, 0);
141*4882a593Smuzhiyun 	if (res)
142*4882a593Smuzhiyun 		goto out;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	switch (be16_to_cpu(*((__be16 *)data))) {
145*4882a593Smuzhiyun 	case HFS_OLD_PMAP_MAGIC:
146*4882a593Smuzhiyun 		res = hfs_parse_old_pmap(sb, data, part_start, part_size);
147*4882a593Smuzhiyun 		break;
148*4882a593Smuzhiyun 	case HFS_NEW_PMAP_MAGIC:
149*4882a593Smuzhiyun 		res = hfs_parse_new_pmap(sb, buf, data, part_start, part_size);
150*4882a593Smuzhiyun 		break;
151*4882a593Smuzhiyun 	default:
152*4882a593Smuzhiyun 		res = -ENOENT;
153*4882a593Smuzhiyun 		break;
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun out:
156*4882a593Smuzhiyun 	kfree(buf);
157*4882a593Smuzhiyun 	return res;
158*4882a593Smuzhiyun }
159