2 * linux/fs/hfsplus/wrapper.c
5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
8 * Handling of HFS wrappers around HFS+ volumes
12 #include <linux/blkdev.h>
13 #include <linux/version.h>
14 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
15 #include <linux/buffer_head.h>
17 #include <asm/unaligned.h>
19 #include "hfsplus_fs.h"
20 #include "hfsplus_raw.h"
29 static int hfsplus_read_mdb(unsigned char *bufptr, struct hfsplus_wd *wd)
34 if (be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG)) != HFSPLUS_VOLHEAD_SIG)
37 attrib = be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_ATTRIB));
38 if (!(attrib & HFSP_WRAP_ATTRIB_SLOCK) ||
39 !(attrib & HFSP_WRAP_ATTRIB_SPARED))
42 wd->ablk_size = be32_to_cpu(*(u32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE));
43 if (wd->ablk_size < HFSPLUS_SECTOR_SIZE)
45 if (wd->ablk_size % HFSPLUS_SECTOR_SIZE)
47 wd->ablk_start = be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
49 extent = be32_to_cpu(get_unaligned((u32 *)(bufptr + HFSP_WRAPOFF_EMBEDEXT)));
50 wd->embed_start = (extent >> 16) & 0xFFFF;
51 wd->embed_count = extent & 0xFFFF;
56 /* Find the volume header and fill in some minimum bits in superblock */
57 /* Takes in super block, returns true if good data read */
58 int hfsplus_read_wrapper(struct super_block *sb)
60 struct buffer_head *bh;
61 struct hfsplus_vh *vhdr;
63 unsigned long block, offset, vhsect;
65 u32 blocksize, blockoffset;
68 blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE);
70 printk("HFS+-fs: unable to configure block size\n");
74 block = (HFSPLUS_VOLHEAD_SECTOR * HFSPLUS_SECTOR_SIZE) / blocksize;
75 offset = (HFSPLUS_VOLHEAD_SECTOR * HFSPLUS_SECTOR_SIZE) % blocksize;
77 bh = sb_bread(sb, block);
79 printk("HFS+-fs: unable to read VHDR or MDB\n");
83 bufptr = bh->b_data + offset;
84 sig = be16_to_cpu(*(u16 *)(bufptr + HFSP_WRAPOFF_SIG));
85 if (sig == HFSP_WRAP_MAGIC) {
86 if (!hfsplus_read_mdb(bufptr, &wd))
88 vhsect = (wd.ablk_start + wd.embed_start * (wd.ablk_size >> 9))
89 + HFSPLUS_VOLHEAD_SECTOR;
90 block = (vhsect * HFSPLUS_SECTOR_SIZE) / blocksize;
91 offset = (vhsect * HFSPLUS_SECTOR_SIZE) % blocksize;
93 bh = sb_bread(sb, block);
95 printk("HFS+-fs: unable to read VHDR\n");
98 HFSPLUS_SB(sb).sect_count = wd.embed_count * (wd.ablk_size >> 9);
101 wd.ablk_size = blocksize;
103 HFSPLUS_SB(sb).sect_count = sb->s_bdev->bd_inode->i_size >> 9;
105 vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
106 if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG)
108 blocksize = be32_to_cpu(vhdr->blocksize);
111 /* block size must be at least as large as a sector
112 * and a multiple of 2
114 if (blocksize < HFSPLUS_SECTOR_SIZE ||
115 ((blocksize - 1) & blocksize))
118 /* block offset must be a multiple of the block size */
119 blockoffset = wd.ablk_start + wd.embed_start * (wd.ablk_size >> 9);
120 if (blockoffset % (blocksize / HFSPLUS_SECTOR_SIZE)) {
121 printk("HFS+-fs: embedded blocks not aligned with wrapper\n");
124 blockoffset /= blocksize / HFSPLUS_SECTOR_SIZE;
125 HFSPLUS_SB(sb).blockoffset = blockoffset;
127 if (sb_set_blocksize(sb, blocksize) != blocksize)
130 block = blockoffset + HFSPLUS_VOLHEAD_SECTOR /
131 (blocksize / HFSPLUS_SECTOR_SIZE);
132 offset = (HFSPLUS_VOLHEAD_SECTOR * HFSPLUS_SECTOR_SIZE) % blocksize;
133 bh = sb_bread(sb, block);
135 printk("HFS+-fs: unable to read VHDR or MDB\n");
138 vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
139 /* should still be the same... */
140 if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG)
142 HFSPLUS_SB(sb).s_vhbh = bh;
143 HFSPLUS_SB(sb).s_vhdr = vhdr;