1 /*
2 * linux/fs/hfs/part_tbl.c
3 *
4 * Copyright (C) 1996-1997 Paul H. Hargrove
5 * This file may be distributed under the terms of the GNU General Public License.
6 *
7 * Original code to handle the new style Mac partition table based on
8 * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
9 *
10 * "XXX" in a comment is a note to myself to consider changing something.
11 *
12 * In function preconditions the term "valid" applied to a pointer to
13 * a structure means that the pointer is non-NULL and the structure it
14 * points to has all fields initialized to consistent values.
15 *
16 * The code in this file initializes some structures which contain
17 * pointers by calling memset(&foo, 0, sizeof(foo)).
18 * This produces the desired behavior only due to the non-ANSI
19 * assumption that the machine representation of NULL is all zeros.
20 */
21
22 #include "hfs.h"
23
24 /*================ File-local data types ================*/
25
26 /*
27 * The Macintosh Driver Descriptor Block
28 *
29 * On partitioned Macintosh media this is block 0.
30 * We really only need the "magic number" to check for partitioned media.
31 */
32 struct hfs_drvr_desc {
33 hfs_word_t ddSig; /* The signature word */
34 /* a bunch more stuff we don't need */
35 };
36
37 /*
38 * The new style Mac partition map
39 *
40 * For each partition on the media there is a physical block (512-byte
41 * block) containing one of these structures. These blocks are
42 * contiguous starting at block 1.
43 */
44 struct new_pmap {
45 hfs_word_t pmSig; /* Signature bytes to verify
46 that this is a partition
47 map block */
48 hfs_word_t reSigPad; /* padding */
49 hfs_lword_t pmMapBlkCnt; /* (At least in block 1) this
50 is the number of partition
51 map blocks */
52 hfs_lword_t pmPyPartStart; /* The physical block number
53 of the first block in this
54 partition */
55 hfs_lword_t pmPartBlkCnt; /* The number of physical
56 blocks in this partition */
57 hfs_byte_t pmPartName[32]; /* (null terminated?) string
58 giving the name of this
59 partition */
60 hfs_byte_t pmPartType[32]; /* (null terminated?) string
61 giving the type of this
62 partition */
63 /* a bunch more stuff we don't need */
64 };
65
66 /*
67 * The old style Mac partition map
68 *
69 * The partition map consists for a 2-byte signature followed by an
70 * array of these structures. The map is terminated with an all-zero
71 * one of these.
72 */
73 struct old_pmap {
74 hfs_word_t pdSig; /* Signature bytes */
75 struct old_pmap_entry {
76 hfs_lword_t pdStart;
77 hfs_lword_t pdSize;
78 hfs_lword_t pdFSID;
79 } pdEntry[42];
80 } __attribute__((packed));
81
82 /*================ File-local functions ================*/
83
84 /*
85 * parse_new_part_table()
86 *
87 * Parse a new style partition map looking for the
88 * start and length of the 'part'th HFS partition.
89 */
parse_new_part_table(hfs_sysmdb sys_mdb,hfs_buffer buf,int part,hfs_s32 * size,hfs_s32 * start)90 static int parse_new_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf,
91 int part, hfs_s32 *size, hfs_s32 *start)
92 {
93 struct new_pmap *pm = (struct new_pmap *)hfs_buffer_data(buf);
94 hfs_u32 pmap_entries = hfs_get_hl(pm->pmMapBlkCnt);
95 int hfs_part = 0;
96 int entry;
97
98 for (entry = 0; (entry < pmap_entries) && !(*start); ++entry) {
99 if (entry) {
100 /* read the next partition map entry */
101 buf = hfs_buffer_get(sys_mdb, HFS_PMAP_BLK + entry, 1);
102 if (!hfs_buffer_ok(buf)) {
103 hfs_warn("hfs_fs: unable to "
104 "read partition map.\n");
105 goto bail;
106 }
107 pm = (struct new_pmap *)hfs_buffer_data(buf);
108 if (hfs_get_ns(pm->pmSig) !=
109 htons(HFS_NEW_PMAP_MAGIC)) {
110 hfs_warn("hfs_fs: invalid "
111 "entry in partition map\n");
112 hfs_buffer_put(buf);
113 goto bail;
114 }
115 }
116
117 /* look for an HFS partition */
118 if (!memcmp(pm->pmPartType,"Apple_HFS",9) &&
119 ((hfs_part++) == part)) {
120 /* Found it! */
121 *start = hfs_get_hl(pm->pmPyPartStart);
122 *size = hfs_get_hl(pm->pmPartBlkCnt);
123 }
124
125 hfs_buffer_put(buf);
126 }
127
128 return 0;
129
130 bail:
131 return 1;
132 }
133
134 /*
135 * parse_old_part_table()
136 *
137 * Parse a old style partition map looking for the
138 * start and length of the 'part'th HFS partition.
139 */
parse_old_part_table(hfs_sysmdb sys_mdb,hfs_buffer buf,int part,hfs_s32 * size,hfs_s32 * start)140 static int parse_old_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf,
141 int part, hfs_s32 *size, hfs_s32 *start)
142 {
143 struct old_pmap *pm = (struct old_pmap *)hfs_buffer_data(buf);
144 struct old_pmap_entry *p = &pm->pdEntry[0];
145 int hfs_part = 0;
146
147 while ((p->pdStart || p->pdSize || p->pdFSID) && !(*start)) {
148 /* look for an HFS partition */
149 if ((hfs_get_nl(p->pdFSID) == htonl(0x54465331)/*"TFS1"*/) &&
150 ((hfs_part++) == part)) {
151 /* Found it! */
152 *start = hfs_get_hl(p->pdStart);
153 *size = hfs_get_hl(p->pdSize);
154 }
155 ++p;
156 }
157 hfs_buffer_put(buf);
158
159 return 0;
160 }
161
162 /*================ Global functions ================*/
163
164 /*
165 * hfs_part_find()
166 *
167 * Parse the partition map looking for the
168 * start and length of the 'part'th HFS partition.
169 */
hfs_part_find(hfs_sysmdb sys_mdb,int part,int silent,hfs_s32 * size,hfs_s32 * start)170 int hfs_part_find(hfs_sysmdb sys_mdb, int part, int silent,
171 hfs_s32 *size, hfs_s32 *start)
172 {
173 hfs_buffer buf;
174 hfs_u16 sig;
175 int dd_found = 0;
176 int retval = 1;
177
178 /* Read block 0 to see if this media is partitioned */
179 buf = hfs_buffer_get(sys_mdb, HFS_DD_BLK, 1);
180 if (!hfs_buffer_ok(buf)) {
181 hfs_warn("hfs_fs: Unable to read block 0.\n");
182 goto done;
183 }
184 sig = hfs_get_ns(((struct hfs_drvr_desc *)hfs_buffer_data(buf))->ddSig);
185 hfs_buffer_put(buf);
186
187 if (sig == htons(HFS_DRVR_DESC_MAGIC)) {
188 /* We are definitely on partitioned media. */
189 dd_found = 1;
190 }
191
192 buf = hfs_buffer_get(sys_mdb, HFS_PMAP_BLK, 1);
193 if (!hfs_buffer_ok(buf)) {
194 hfs_warn("hfs_fs: Unable to read block 1.\n");
195 goto done;
196 }
197
198 *size = *start = 0;
199
200 switch (hfs_get_ns(hfs_buffer_data(buf))) {
201 case __constant_htons(HFS_OLD_PMAP_MAGIC):
202 retval = parse_old_part_table(sys_mdb, buf, part, size, start);
203 break;
204
205 case __constant_htons(HFS_NEW_PMAP_MAGIC):
206 retval = parse_new_part_table(sys_mdb, buf, part, size, start);
207 break;
208
209 default:
210 if (dd_found) {
211 /* The media claimed to have a partition map */
212 if (!silent) {
213 hfs_warn("hfs_fs: This disk has an "
214 "unrecognized partition map type.\n");
215 }
216 } else {
217 /* Conclude that the media is not partitioned */
218 retval = 0;
219 }
220 goto done;
221 }
222
223 if (!retval) {
224 if (*start == 0) {
225 if (part) {
226 hfs_warn("hfs_fs: unable to locate "
227 "HFS partition number %d.\n", part);
228 } else {
229 hfs_warn("hfs_fs: unable to locate any "
230 "HFS partitions.\n");
231 }
232 retval = 1;
233 } else if (*size < 0) {
234 hfs_warn("hfs_fs: Partition size > 1 Terabyte.\n");
235 retval = 1;
236 } else if (*start < 0) {
237 hfs_warn("hfs_fs: Partition begins beyond 1 "
238 "Terabyte.\n");
239 retval = 1;
240 }
241 }
242 done:
243 return retval;
244 }
245