Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/fs/hfsplus/part_tbl.c
0003  *
0004  * Copyright (C) 1996-1997  Paul H. Hargrove
0005  * This file may be distributed under the terms of
0006  * the GNU General Public License.
0007  *
0008  * Original code to handle the new style Mac partition table based on
0009  * a patch contributed by Holger Schemel (aeglos@valinor.owl.de).
0010  *
0011  * In function preconditions the term "valid" applied to a pointer to
0012  * a structure means that the pointer is non-NULL and the structure it
0013  * points to has all fields initialized to consistent values.
0014  *
0015  */
0016 
0017 #include <linux/slab.h>
0018 #include "hfsplus_fs.h"
0019 
0020 /* offsets to various blocks */
0021 #define HFS_DD_BLK      0 /* Driver Descriptor block */
0022 #define HFS_PMAP_BLK        1 /* First block of partition map */
0023 #define HFS_MDB_BLK     2 /* Block (w/i partition) of MDB */
0024 
0025 /* magic numbers for various disk blocks */
0026 #define HFS_DRVR_DESC_MAGIC 0x4552 /* "ER": driver descriptor map */
0027 #define HFS_OLD_PMAP_MAGIC  0x5453 /* "TS": old-type partition map */
0028 #define HFS_NEW_PMAP_MAGIC  0x504D /* "PM": new-type partition map */
0029 #define HFS_SUPER_MAGIC     0x4244 /* "BD": HFS MDB (super block) */
0030 #define HFS_MFS_SUPER_MAGIC 0xD2D7 /* MFS MDB (super block) */
0031 
0032 /*
0033  * The new style Mac partition map
0034  *
0035  * For each partition on the media there is a physical block (512-byte
0036  * block) containing one of these structures.  These blocks are
0037  * contiguous starting at block 1.
0038  */
0039 struct new_pmap {
0040     __be16  pmSig;      /* signature */
0041     __be16  reSigPad;   /* padding */
0042     __be32  pmMapBlkCnt;    /* partition blocks count */
0043     __be32  pmPyPartStart;  /* physical block start of partition */
0044     __be32  pmPartBlkCnt;   /* physical block count of partition */
0045     u8  pmPartName[32]; /* (null terminated?) string
0046                    giving the name of this
0047                    partition */
0048     u8  pmPartType[32]; /* (null terminated?) string
0049                    giving the type of this
0050                    partition */
0051     /* a bunch more stuff we don't need */
0052 } __packed;
0053 
0054 /*
0055  * The old style Mac partition map
0056  *
0057  * The partition map consists for a 2-byte signature followed by an
0058  * array of these structures.  The map is terminated with an all-zero
0059  * one of these.
0060  */
0061 struct old_pmap {
0062     __be16      pdSig;  /* Signature bytes */
0063     struct old_pmap_entry {
0064         __be32  pdStart;
0065         __be32  pdSize;
0066         __be32  pdFSID;
0067     }   pdEntry[42];
0068 } __packed;
0069 
0070 static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm,
0071         sector_t *part_start, sector_t *part_size)
0072 {
0073     struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
0074     int i;
0075 
0076     for (i = 0; i < 42; i++) {
0077         struct old_pmap_entry *p = &pm->pdEntry[i];
0078 
0079         if (p->pdStart && p->pdSize &&
0080             p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
0081             (sbi->part < 0 || sbi->part == i)) {
0082             *part_start += be32_to_cpu(p->pdStart);
0083             *part_size = be32_to_cpu(p->pdSize);
0084             return 0;
0085         }
0086     }
0087 
0088     return -ENOENT;
0089 }
0090 
0091 static int hfs_parse_new_pmap(struct super_block *sb, void *buf,
0092         struct new_pmap *pm, sector_t *part_start, sector_t *part_size)
0093 {
0094     struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
0095     int size = be32_to_cpu(pm->pmMapBlkCnt);
0096     int buf_size = hfsplus_min_io_size(sb);
0097     int res;
0098     int i = 0;
0099 
0100     do {
0101         if (!memcmp(pm->pmPartType, "Apple_HFS", 9) &&
0102             (sbi->part < 0 || sbi->part == i)) {
0103             *part_start += be32_to_cpu(pm->pmPyPartStart);
0104             *part_size = be32_to_cpu(pm->pmPartBlkCnt);
0105             return 0;
0106         }
0107 
0108         if (++i >= size)
0109             return -ENOENT;
0110 
0111         pm = (struct new_pmap *)((u8 *)pm + HFSPLUS_SECTOR_SIZE);
0112         if ((u8 *)pm - (u8 *)buf >= buf_size) {
0113             res = hfsplus_submit_bio(sb,
0114                          *part_start + HFS_PMAP_BLK + i,
0115                          buf, (void **)&pm, REQ_OP_READ);
0116             if (res)
0117                 return res;
0118         }
0119     } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC));
0120 
0121     return -ENOENT;
0122 }
0123 
0124 /*
0125  * Parse the partition map looking for the start and length of a
0126  * HFS/HFS+ partition.
0127  */
0128 int hfs_part_find(struct super_block *sb,
0129         sector_t *part_start, sector_t *part_size)
0130 {
0131     void *buf, *data;
0132     int res;
0133 
0134     buf = kmalloc(hfsplus_min_io_size(sb), GFP_KERNEL);
0135     if (!buf)
0136         return -ENOMEM;
0137 
0138     res = hfsplus_submit_bio(sb, *part_start + HFS_PMAP_BLK,
0139                  buf, &data, REQ_OP_READ);
0140     if (res)
0141         goto out;
0142 
0143     switch (be16_to_cpu(*((__be16 *)data))) {
0144     case HFS_OLD_PMAP_MAGIC:
0145         res = hfs_parse_old_pmap(sb, data, part_start, part_size);
0146         break;
0147     case HFS_NEW_PMAP_MAGIC:
0148         res = hfs_parse_new_pmap(sb, buf, data, part_start, part_size);
0149         break;
0150     default:
0151         res = -ENOENT;
0152         break;
0153     }
0154 out:
0155     kfree(buf);
0156     return res;
0157 }