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