1/* 2 * linux/fs/hfsplus/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 * In function preconditions the term "valid" applied to a pointer to 11 * a structure means that the pointer is non-NULL and the structure it 12 * points to has all fields initialized to consistent values. 13 * 14 */ 15 16#include <linux/slab.h> 17#include "hfsplus_fs.h" 18 19/* offsets to various blocks */ 20#define HFS_DD_BLK 0 /* Driver Descriptor block */ 21#define HFS_PMAP_BLK 1 /* First block of partition map */ 22#define HFS_MDB_BLK 2 /* Block (w/i partition) of MDB */ 23 24/* magic numbers for various disk blocks */ 25#define HFS_DRVR_DESC_MAGIC 0x4552 /* "ER": driver descriptor map */ 26#define HFS_OLD_PMAP_MAGIC 0x5453 /* "TS": old-type partition map */ 27#define HFS_NEW_PMAP_MAGIC 0x504D /* "PM": new-type partition map */ 28#define HFS_SUPER_MAGIC 0x4244 /* "BD": HFS MDB (super block) */ 29#define HFS_MFS_SUPER_MAGIC 0xD2D7 /* MFS MDB (super block) */ 30 31/* 32 * The new style Mac partition map 33 * 34 * For each partition on the media there is a physical block (512-byte 35 * block) containing one of these structures. These blocks are 36 * contiguous starting at block 1. 37 */ 38struct new_pmap { 39 __be16 pmSig; /* signature */ 40 __be16 reSigPad; /* padding */ 41 __be32 pmMapBlkCnt; /* partition blocks count */ 42 __be32 pmPyPartStart; /* physical block start of partition */ 43 __be32 pmPartBlkCnt; /* physical block count of partition */ 44 u8 pmPartName[32]; /* (null terminated?) string 45 giving the name of this 46 partition */ 47 u8 pmPartType[32]; /* (null terminated?) string 48 giving the type of this 49 partition */ 50 /* a bunch more stuff we don't need */ 51} __packed; 52 53/* 54 * The old style Mac partition map 55 * 56 * The partition map consists for a 2-byte signature followed by an 57 * array of these structures. The map is terminated with an all-zero 58 * one of these. 59 */ 60struct old_pmap { 61 __be16 pdSig; /* Signature bytes */ 62 struct old_pmap_entry { 63 __be32 pdStart; 64 __be32 pdSize; 65 __be32 pdFSID; 66 } pdEntry[42]; 67} __packed; 68 69static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm, 70 sector_t *part_start, sector_t *part_size) 71{ 72 struct hfsplus_sb_info sbi = HFSPLUS_SB(sb); 73 int i; 74 75 for (i = 0; i < 42; i++) { 76 struct old_pmap_entry *p = &pm->pdEntry[i]; 77 78 if (p->pdStart && p->pdSize && 79 p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ && 80 (sbi.part < 0 || sbi.part == i)) { 81 *part_start += be32_to_cpu(p->pdStart); 82 *part_size = be32_to_cpu(p->pdSize); 83 return 0; 84 } 85 } 86 87 return -ENOENT; 88} 89 90static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm, 91 sector_t *part_start, sector_t *part_size) 92{ 93 int size = be32_to_cpu(pm->pmMapBlkCnt); 94 int res; 95 int i = 0; 96 97 do { 98 if (!memcmp(pm->pmPartType, "Apple_HFS", 9) && 99 (HFSPLUS_SB(sb).part < 0 || HFSPLUS_SB(sb).part == i)) { 100 *part_start += be32_to_cpu(pm->pmPyPartStart); 101 *part_size = be32_to_cpu(pm->pmPartBlkCnt); 102 return 0; 103 } 104 105 if (++i >= size) 106 return -ENOENT; 107 108 res = hfsplus_submit_bio(sb->s_bdev, 109 *part_start + HFS_PMAP_BLK + i, 110 pm, READ); 111 if (res) 112 return res; 113 } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC)); 114 115 return -ENOENT; 116} 117 118 119/* 120 * hfs_part_find() 121 * 122 * Parse the partition map looking for the 123 * start and length of the 'part'th HFS partition. 124 */ 125int hfs_part_find(struct super_block *sb, 126 sector_t *part_start, sector_t *part_size) 127{ 128 void *data; 129 int res; 130 131 data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL); 132 if (!data) 133 return -ENOMEM; 134 135 res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK, 136 data, READ); 137 if (res) 138 goto out; 139 140 switch (be16_to_cpu(*((__be16 *)data))) { 141 case HFS_OLD_PMAP_MAGIC: 142 res = hfs_parse_old_pmap(sb, data, part_start, part_size); 143 break; 144 case HFS_NEW_PMAP_MAGIC: 145 res = hfs_parse_new_pmap(sb, data, part_start, part_size); 146 break; 147 default: 148 res = -ENOENT; 149 break; 150 } 151out: 152 kfree(data); 153 154 return res; 155} 156