File: /usr/src/linux/fs/hfs/part_tbl.c

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      */
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      */
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      */
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