11da177e4SLinus Torvalds /* 2f30c2269SUwe Zeisberger * linux/fs/hfsplus/part_tbl.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1996-1997 Paul H. Hargrove 52753cc28SAnton Salikhmetov * This file may be distributed under the terms of 62753cc28SAnton Salikhmetov * the GNU General Public License. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Original code to handle the new style Mac partition table based on 91da177e4SLinus Torvalds * a patch contributed by Holger Schemel (aeglos@valinor.owl.de). 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * In function preconditions the term "valid" applied to a pointer to 121da177e4SLinus Torvalds * a structure means that the pointer is non-NULL and the structure it 131da177e4SLinus Torvalds * points to has all fields initialized to consistent values. 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 17358f26d5SChristoph Hellwig #include <linux/slab.h> 181da177e4SLinus Torvalds #include "hfsplus_fs.h" 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds /* offsets to various blocks */ 211da177e4SLinus Torvalds #define HFS_DD_BLK 0 /* Driver Descriptor block */ 221da177e4SLinus Torvalds #define HFS_PMAP_BLK 1 /* First block of partition map */ 231da177e4SLinus Torvalds #define HFS_MDB_BLK 2 /* Block (w/i partition) of MDB */ 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds /* magic numbers for various disk blocks */ 261da177e4SLinus Torvalds #define HFS_DRVR_DESC_MAGIC 0x4552 /* "ER": driver descriptor map */ 271da177e4SLinus Torvalds #define HFS_OLD_PMAP_MAGIC 0x5453 /* "TS": old-type partition map */ 281da177e4SLinus Torvalds #define HFS_NEW_PMAP_MAGIC 0x504D /* "PM": new-type partition map */ 291da177e4SLinus Torvalds #define HFS_SUPER_MAGIC 0x4244 /* "BD": HFS MDB (super block) */ 301da177e4SLinus Torvalds #define HFS_MFS_SUPER_MAGIC 0xD2D7 /* MFS MDB (super block) */ 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds /* 331da177e4SLinus Torvalds * The new style Mac partition map 341da177e4SLinus Torvalds * 351da177e4SLinus Torvalds * For each partition on the media there is a physical block (512-byte 361da177e4SLinus Torvalds * block) containing one of these structures. These blocks are 371da177e4SLinus Torvalds * contiguous starting at block 1. 381da177e4SLinus Torvalds */ 391da177e4SLinus Torvalds struct new_pmap { 401da177e4SLinus Torvalds __be16 pmSig; /* signature */ 411da177e4SLinus Torvalds __be16 reSigPad; /* padding */ 421da177e4SLinus Torvalds __be32 pmMapBlkCnt; /* partition blocks count */ 431da177e4SLinus Torvalds __be32 pmPyPartStart; /* physical block start of partition */ 441da177e4SLinus Torvalds __be32 pmPartBlkCnt; /* physical block count of partition */ 451da177e4SLinus Torvalds u8 pmPartName[32]; /* (null terminated?) string 461da177e4SLinus Torvalds giving the name of this 471da177e4SLinus Torvalds partition */ 481da177e4SLinus Torvalds u8 pmPartType[32]; /* (null terminated?) string 491da177e4SLinus Torvalds giving the type of this 501da177e4SLinus Torvalds partition */ 511da177e4SLinus Torvalds /* a bunch more stuff we don't need */ 521da177e4SLinus Torvalds } __packed; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /* 551da177e4SLinus Torvalds * The old style Mac partition map 561da177e4SLinus Torvalds * 571da177e4SLinus Torvalds * The partition map consists for a 2-byte signature followed by an 581da177e4SLinus Torvalds * array of these structures. The map is terminated with an all-zero 591da177e4SLinus Torvalds * one of these. 601da177e4SLinus Torvalds */ 611da177e4SLinus Torvalds struct old_pmap { 621da177e4SLinus Torvalds __be16 pdSig; /* Signature bytes */ 631da177e4SLinus Torvalds struct old_pmap_entry { 641da177e4SLinus Torvalds __be32 pdStart; 651da177e4SLinus Torvalds __be32 pdSize; 661da177e4SLinus Torvalds __be32 pdFSID; 671da177e4SLinus Torvalds } pdEntry[42]; 681da177e4SLinus Torvalds } __packed; 691da177e4SLinus Torvalds 70358f26d5SChristoph Hellwig static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm, 711da177e4SLinus Torvalds sector_t *part_start, sector_t *part_size) 721da177e4SLinus Torvalds { 73dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 74358f26d5SChristoph Hellwig int i; 751da177e4SLinus Torvalds 76358f26d5SChristoph Hellwig for (i = 0; i < 42; i++) { 77358f26d5SChristoph Hellwig struct old_pmap_entry *p = &pm->pdEntry[i]; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds if (p->pdStart && p->pdSize && 801da177e4SLinus Torvalds p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ && 81dd73a01aSChristoph Hellwig (sbi->part < 0 || sbi->part == i)) { 821da177e4SLinus Torvalds *part_start += be32_to_cpu(p->pdStart); 831da177e4SLinus Torvalds *part_size = be32_to_cpu(p->pdSize); 84358f26d5SChristoph Hellwig return 0; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 88358f26d5SChristoph Hellwig return -ENOENT; 89358f26d5SChristoph Hellwig } 90358f26d5SChristoph Hellwig 91*6596528eSSeth Forshee static int hfs_parse_new_pmap(struct super_block *sb, void *buf, 92*6596528eSSeth Forshee struct new_pmap *pm, sector_t *part_start, sector_t *part_size) 93358f26d5SChristoph Hellwig { 94358f26d5SChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 95358f26d5SChristoph Hellwig int size = be32_to_cpu(pm->pmMapBlkCnt); 96*6596528eSSeth Forshee int buf_size = hfsplus_min_io_size(sb); 97358f26d5SChristoph Hellwig int res; 98358f26d5SChristoph Hellwig int i = 0; 99358f26d5SChristoph Hellwig 100358f26d5SChristoph Hellwig do { 1011da177e4SLinus Torvalds if (!memcmp(pm->pmPartType, "Apple_HFS", 9) && 102dd73a01aSChristoph Hellwig (sbi->part < 0 || sbi->part == i)) { 1031da177e4SLinus Torvalds *part_start += be32_to_cpu(pm->pmPyPartStart); 1041da177e4SLinus Torvalds *part_size = be32_to_cpu(pm->pmPartBlkCnt); 105358f26d5SChristoph Hellwig return 0; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 108358f26d5SChristoph Hellwig if (++i >= size) 109358f26d5SChristoph Hellwig return -ENOENT; 110358f26d5SChristoph Hellwig 111*6596528eSSeth Forshee pm = (struct new_pmap *)((u8 *)pm + HFSPLUS_SECTOR_SIZE); 112*6596528eSSeth Forshee if ((u8 *)pm - (u8 *)buf >= buf_size) { 113*6596528eSSeth Forshee res = hfsplus_submit_bio(sb, 114358f26d5SChristoph Hellwig *part_start + HFS_PMAP_BLK + i, 115*6596528eSSeth Forshee buf, (void **)&pm, READ); 116358f26d5SChristoph Hellwig if (res) 117358f26d5SChristoph Hellwig return res; 118*6596528eSSeth Forshee } 119358f26d5SChristoph Hellwig } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC)); 120358f26d5SChristoph Hellwig 121358f26d5SChristoph Hellwig return -ENOENT; 122358f26d5SChristoph Hellwig } 123358f26d5SChristoph Hellwig 124358f26d5SChristoph Hellwig /* 125358f26d5SChristoph Hellwig * Parse the partition map looking for the start and length of a 126358f26d5SChristoph Hellwig * HFS/HFS+ partition. 127358f26d5SChristoph Hellwig */ 128358f26d5SChristoph Hellwig int hfs_part_find(struct super_block *sb, 129358f26d5SChristoph Hellwig sector_t *part_start, sector_t *part_size) 130358f26d5SChristoph Hellwig { 131*6596528eSSeth Forshee void *buf, *data; 132358f26d5SChristoph Hellwig int res; 133358f26d5SChristoph Hellwig 134*6596528eSSeth Forshee buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL); 135*6596528eSSeth Forshee if (!buf) 136358f26d5SChristoph Hellwig return -ENOMEM; 137358f26d5SChristoph Hellwig 138*6596528eSSeth Forshee res = hfsplus_submit_bio(sb, *part_start + HFS_PMAP_BLK, 139*6596528eSSeth Forshee buf, &data, READ); 140358f26d5SChristoph Hellwig if (res) 14114dd01f8SChuck Ebbert goto out; 142358f26d5SChristoph Hellwig 143358f26d5SChristoph Hellwig switch (be16_to_cpu(*((__be16 *)data))) { 144358f26d5SChristoph Hellwig case HFS_OLD_PMAP_MAGIC: 145358f26d5SChristoph Hellwig res = hfs_parse_old_pmap(sb, data, part_start, part_size); 146358f26d5SChristoph Hellwig break; 147358f26d5SChristoph Hellwig case HFS_NEW_PMAP_MAGIC: 148*6596528eSSeth Forshee res = hfs_parse_new_pmap(sb, buf, data, part_start, part_size); 149358f26d5SChristoph Hellwig break; 150358f26d5SChristoph Hellwig default: 151358f26d5SChristoph Hellwig res = -ENOENT; 152358f26d5SChristoph Hellwig break; 153358f26d5SChristoph Hellwig } 15414dd01f8SChuck Ebbert out: 155*6596528eSSeth Forshee kfree(buf); 1561da177e4SLinus Torvalds return res; 1571da177e4SLinus Torvalds } 158