1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/slab.h>
18#include "hfsplus_fs.h"
19
20
21#define HFS_DD_BLK 0
22#define HFS_PMAP_BLK 1
23#define HFS_MDB_BLK 2
24
25
26#define HFS_DRVR_DESC_MAGIC 0x4552
27#define HFS_OLD_PMAP_MAGIC 0x5453
28#define HFS_NEW_PMAP_MAGIC 0x504D
29#define HFS_SUPER_MAGIC 0x4244
30#define HFS_MFS_SUPER_MAGIC 0xD2D7
31
32
33
34
35
36
37
38
39struct new_pmap {
40 __be16 pmSig;
41 __be16 reSigPad;
42 __be32 pmMapBlkCnt;
43 __be32 pmPyPartStart;
44 __be32 pmPartBlkCnt;
45 u8 pmPartName[32];
46
47
48 u8 pmPartType[32];
49
50
51
52} __packed;
53
54
55
56
57
58
59
60
61struct old_pmap {
62 __be16 pdSig;
63 struct old_pmap_entry {
64 __be32 pdStart;
65 __be32 pdSize;
66 __be32 pdFSID;
67 } pdEntry[42];
68} __packed;
69
70static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
71 sector_t *part_start, sector_t *part_size)
72{
73 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
74 int i;
75
76 for (i = 0; i < 42; i++) {
77 struct old_pmap_entry *p = &pm->pdEntry[i];
78
79 if (p->pdStart && p->pdSize &&
80 p->pdFSID == cpu_to_be32(0x54465331) &&
81 (sbi->part < 0 || sbi->part == i)) {
82 *part_start += be32_to_cpu(p->pdStart);
83 *part_size = be32_to_cpu(p->pdSize);
84 return 0;
85 }
86 }
87
88 return -ENOENT;
89}
90
91static int hfs_parse_new_pmap(struct super_block *sb, void *buf,
92 struct new_pmap *pm, sector_t *part_start, sector_t *part_size)
93{
94 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
95 int size = be32_to_cpu(pm->pmMapBlkCnt);
96 int buf_size = hfsplus_min_io_size(sb);
97 int res;
98 int i = 0;
99
100 do {
101 if (!memcmp(pm->pmPartType, "Apple_HFS", 9) &&
102 (sbi->part < 0 || sbi->part == i)) {
103 *part_start += be32_to_cpu(pm->pmPyPartStart);
104 *part_size = be32_to_cpu(pm->pmPartBlkCnt);
105 return 0;
106 }
107
108 if (++i >= size)
109 return -ENOENT;
110
111 pm = (struct new_pmap *)((u8 *)pm + HFSPLUS_SECTOR_SIZE);
112 if ((u8 *)pm - (u8 *)buf >= buf_size) {
113 res = hfsplus_submit_bio(sb,
114 *part_start + HFS_PMAP_BLK + i,
115 buf, (void **)&pm, REQ_OP_READ,
116 0);
117 if (res)
118 return res;
119 }
120 } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));
121
122 return -ENOENT;
123}
124
125
126
127
128
129int hfs_part_find(struct super_block *sb,
130 sector_t *part_start, sector_t *part_size)
131{
132 void *buf, *data;
133 int res;
134
135 buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
136 if (!buf)
137 return -ENOMEM;
138
139 res = hfsplus_submit_bio(sb, *part_start + HFS_PMAP_BLK,
140 buf, &data, REQ_OP_READ, 0);
141 if (res)
142 goto out;
143
144 switch (be16_to_cpu(*((__be16 *)data))) {
145 case HFS_OLD_PMAP_MAGIC:
146 res = hfs_parse_old_pmap(sb, data, part_start, part_size);
147 break;
148 case HFS_NEW_PMAP_MAGIC:
149 res = hfs_parse_new_pmap(sb, buf, data, part_start, part_size);
150 break;
151 default:
152 res = -ENOENT;
153 break;
154 }
155out:
156 kfree(buf);
157 return res;
158}
159