more changes on original files
[linux-2.4.git] / 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 }