/* * linux/fs/hfs/part_tbl.c * * Copyright (C) 1996-1997 Paul H. Hargrove * This file may be distributed under the terms of the GNU General Public License. * * Original code to handle the new style Mac partition table based on * a patch contributed by Holger Schemel (aeglos@valinor.owl.de). * * "XXX" in a comment is a note to myself to consider changing something. * * In function preconditions the term "valid" applied to a pointer to * a structure means that the pointer is non-NULL and the structure it * points to has all fields initialized to consistent values. * * The code in this file initializes some structures which contain * pointers by calling memset(&foo, 0, sizeof(foo)). * This produces the desired behavior only due to the non-ANSI * assumption that the machine representation of NULL is all zeros. */ #include "hfs.h" /*================ File-local data types ================*/ /* * The Macintosh Driver Descriptor Block * * On partitioned Macintosh media this is block 0. * We really only need the "magic number" to check for partitioned media. */ struct hfs_drvr_desc { hfs_word_t ddSig; /* The signature word */ /* a bunch more stuff we don't need */ }; /* * The new style Mac partition map * * For each partition on the media there is a physical block (512-byte * block) containing one of these structures. These blocks are * contiguous starting at block 1. */ struct new_pmap { hfs_word_t pmSig; /* Signature bytes to verify that this is a partition map block */ hfs_word_t reSigPad; /* padding */ hfs_lword_t pmMapBlkCnt; /* (At least in block 1) this is the number of partition map blocks */ hfs_lword_t pmPyPartStart; /* The physical block number of the first block in this partition */ hfs_lword_t pmPartBlkCnt; /* The number of physical blocks in this partition */ hfs_byte_t pmPartName[32]; /* (null terminated?) string giving the name of this partition */ hfs_byte_t pmPartType[32]; /* (null terminated?) string giving the type of this partition */ /* a bunch more stuff we don't need */ }; /* * The old style Mac partition map * * The partition map consists for a 2-byte signature followed by an * array of these structures. The map is terminated with an all-zero * one of these. */ struct old_pmap { hfs_word_t pdSig; /* Signature bytes */ struct old_pmap_entry { hfs_lword_t pdStart; hfs_lword_t pdSize; hfs_lword_t pdFSID; } pdEntry[42]; } __attribute__((packed)); /*================ File-local functions ================*/ /* * parse_new_part_table() * * Parse a new style partition map looking for the * start and length of the 'part'th HFS partition. */ static int parse_new_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf, int part, hfs_s32 *size, hfs_s32 *start) { struct new_pmap *pm = (struct new_pmap *)hfs_buffer_data(buf); hfs_u32 pmap_entries = hfs_get_hl(pm->pmMapBlkCnt); int hfs_part = 0; int entry; for (entry = 0; (entry < pmap_entries) && !(*start); ++entry) { if (entry) { /* read the next partition map entry */ buf = hfs_buffer_get(sys_mdb, HFS_PMAP_BLK + entry, 1); if (!hfs_buffer_ok(buf)) { hfs_warn("hfs_fs: unable to " "read partition map.\n"); goto bail; } pm = (struct new_pmap *)hfs_buffer_data(buf); if (hfs_get_ns(pm->pmSig) != htons(HFS_NEW_PMAP_MAGIC)) { hfs_warn("hfs_fs: invalid " "entry in partition map\n"); hfs_buffer_put(buf); goto bail; } } /* look for an HFS partition */ if (!memcmp(pm->pmPartType,"Apple_HFS",9) && ((hfs_part++) == part)) { /* Found it! */ *start = hfs_get_hl(pm->pmPyPartStart); *size = hfs_get_hl(pm->pmPartBlkCnt); } hfs_buffer_put(buf); } return 0; bail: return 1; } /* * parse_old_part_table() * * Parse a old style partition map looking for the * start and length of the 'part'th HFS partition. */ static int parse_old_part_table(hfs_sysmdb sys_mdb, hfs_buffer buf, int part, hfs_s32 *size, hfs_s32 *start) { struct old_pmap *pm = (struct old_pmap *)hfs_buffer_data(buf); struct old_pmap_entry *p = &pm->pdEntry[0]; int hfs_part = 0; while ((p->pdStart || p->pdSize || p->pdFSID) && !(*start)) { /* look for an HFS partition */ if ((hfs_get_nl(p->pdFSID) == htonl(0x54465331)/*"TFS1"*/) && ((hfs_part++) == part)) { /* Found it! */ *start = hfs_get_hl(p->pdStart); *size = hfs_get_hl(p->pdSize); } ++p; } hfs_buffer_put(buf); return 0; } /*================ Global functions ================*/ /* * hfs_part_find() * * Parse the partition map looking for the * start and length of the 'part'th HFS partition. */ int hfs_part_find(hfs_sysmdb sys_mdb, int part, int silent, hfs_s32 *size, hfs_s32 *start) { hfs_buffer buf; hfs_u16 sig; int dd_found = 0; int retval = 1; /* Read block 0 to see if this media is partitioned */ buf = hfs_buffer_get(sys_mdb, HFS_DD_BLK, 1); if (!hfs_buffer_ok(buf)) { hfs_warn("hfs_fs: Unable to read block 0.\n"); goto done; } sig = hfs_get_ns(((struct hfs_drvr_desc *)hfs_buffer_data(buf))->ddSig); hfs_buffer_put(buf); if (sig == htons(HFS_DRVR_DESC_MAGIC)) { /* We are definitely on partitioned media. */ dd_found = 1; } buf = hfs_buffer_get(sys_mdb, HFS_PMAP_BLK, 1); if (!hfs_buffer_ok(buf)) { hfs_warn("hfs_fs: Unable to read block 1.\n"); goto done; } *size = *start = 0; switch (hfs_get_ns(hfs_buffer_data(buf))) { case __constant_htons(HFS_OLD_PMAP_MAGIC): retval = parse_old_part_table(sys_mdb, buf, part, size, start); break; case __constant_htons(HFS_NEW_PMAP_MAGIC): retval = parse_new_part_table(sys_mdb, buf, part, size, start); break; default: if (dd_found) { /* The media claimed to have a partition map */ if (!silent) { hfs_warn("hfs_fs: This disk has an " "unrecognized partition map type.\n"); } } else { /* Conclude that the media is not partitioned */ retval = 0; } goto done; } if (!retval) { if (*start == 0) { if (part) { hfs_warn("hfs_fs: unable to locate " "HFS partition number %d.\n", part); } else { hfs_warn("hfs_fs: unable to locate any " "HFS partitions.\n"); } retval = 1; } else if (*size < 0) { hfs_warn("hfs_fs: Partition size > 1 Terabyte.\n"); retval = 1; } else if (*start < 0) { hfs_warn("hfs_fs: Partition begins beyond 1 " "Terabyte.\n"); retval = 1; } } done: return retval; }