busybox/util-linux/volume_id/hfs.c
<<
>>
Prefs
   1/*
   2 * volume_id - reads filesystem label and uuid
   3 *
   4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
   5 *
   6 *      This library is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU Lesser General Public
   8 *      License as published by the Free Software Foundation; either
   9 *      version 2.1 of the License, or (at your option) any later version.
  10 *
  11 *      This library is distributed in the hope that it will be useful,
  12 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14 *      Lesser General Public License for more details.
  15 *
  16 *      You should have received a copy of the GNU Lesser General Public
  17 *      License along with this library; if not, write to the Free Software
  18 *      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 */
  20
  21#include "volume_id_internal.h"
  22
  23struct hfs_finder_info{
  24        uint32_t        boot_folder;
  25        uint32_t        start_app;
  26        uint32_t        open_folder;
  27        uint32_t        os9_folder;
  28        uint32_t        reserved;
  29        uint32_t        osx_folder;
  30        uint8_t         id[8];
  31} __attribute__((__packed__));
  32
  33struct hfs_mdb {
  34        uint8_t         signature[2];
  35        uint32_t        cr_date;
  36        uint32_t        ls_Mod;
  37        uint16_t        atrb;
  38        uint16_t        nm_fls;
  39        uint16_t        vbm_st;
  40        uint16_t        alloc_ptr;
  41        uint16_t        nm_al_blks;
  42        uint32_t        al_blk_size;
  43        uint32_t        clp_size;
  44        uint16_t        al_bl_st;
  45        uint32_t        nxt_cnid;
  46        uint16_t        free_bks;
  47        uint8_t         label_len;
  48        uint8_t         label[27];
  49        uint32_t        vol_bkup;
  50        uint16_t        vol_seq_num;
  51        uint32_t        wr_cnt;
  52        uint32_t        xt_clump_size;
  53        uint32_t        ct_clump_size;
  54        uint16_t        num_root_dirs;
  55        uint32_t        file_count;
  56        uint32_t        dir_count;
  57        struct hfs_finder_info finder_info;
  58        uint8_t         embed_sig[2];
  59        uint16_t        embed_startblock;
  60        uint16_t        embed_blockcount;
  61} __attribute__((__packed__));
  62
  63struct hfsplus_bnode_descriptor {
  64        uint32_t        next;
  65        uint32_t        prev;
  66        uint8_t         type;
  67        uint8_t         height;
  68        uint16_t        num_recs;
  69        uint16_t        reserved;
  70} __attribute__((__packed__));
  71
  72struct hfsplus_bheader_record {
  73        uint16_t        depth;
  74        uint32_t        root;
  75        uint32_t        leaf_count;
  76        uint32_t        leaf_head;
  77        uint32_t        leaf_tail;
  78        uint16_t        node_size;
  79} __attribute__((__packed__));
  80
  81struct hfsplus_catalog_key {
  82        uint16_t        key_len;
  83        uint32_t        parent_id;
  84        uint16_t        unicode_len;
  85        uint8_t         unicode[255 * 2];
  86} __attribute__((__packed__));
  87
  88struct hfsplus_extent {
  89        uint32_t        start_block;
  90        uint32_t        block_count;
  91} __attribute__((__packed__));
  92
  93#define HFSPLUS_EXTENT_COUNT            8
  94struct hfsplus_fork {
  95        uint64_t        total_size;
  96        uint32_t        clump_size;
  97        uint32_t        total_blocks;
  98        struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
  99} __attribute__((__packed__));
 100
 101struct hfsplus_vol_header {
 102        uint8_t         signature[2];
 103        uint16_t        version;
 104        uint32_t        attributes;
 105        uint32_t        last_mount_vers;
 106        uint32_t        reserved;
 107        uint32_t        create_date;
 108        uint32_t        modify_date;
 109        uint32_t        backup_date;
 110        uint32_t        checked_date;
 111        uint32_t        file_count;
 112        uint32_t        folder_count;
 113        uint32_t        blocksize;
 114        uint32_t        total_blocks;
 115        uint32_t        free_blocks;
 116        uint32_t        next_alloc;
 117        uint32_t        rsrc_clump_sz;
 118        uint32_t        data_clump_sz;
 119        uint32_t        next_cnid;
 120        uint32_t        write_count;
 121        uint64_t        encodings_bmp;
 122        struct hfs_finder_info finder_info;
 123        struct hfsplus_fork alloc_file;
 124        struct hfsplus_fork ext_file;
 125        struct hfsplus_fork cat_file;
 126        struct hfsplus_fork attr_file;
 127        struct hfsplus_fork start_file;
 128} __attribute__((__packed__));
 129
 130#define HFS_SUPERBLOCK_OFFSET           0x400
 131#define HFS_NODE_LEAF                   0xff
 132#define HFSPLUS_POR_CNID                1
 133
 134int volume_id_probe_hfs_hfsplus(struct volume_id *id /*,uint64_t off*/)
 135{
 136        uint64_t off = 0;
 137        unsigned blocksize;
 138        unsigned cat_block;
 139        unsigned ext_block_start;
 140        unsigned ext_block_count;
 141        int ext;
 142        unsigned leaf_node_head;
 143        unsigned leaf_node_count;
 144        unsigned leaf_node_size;
 145        unsigned leaf_block;
 146        uint64_t leaf_off;
 147        unsigned alloc_block_size;
 148        unsigned alloc_first_block;
 149        unsigned embed_first_block;
 150        unsigned record_count;
 151        struct hfsplus_vol_header *hfsplus;
 152        struct hfsplus_bnode_descriptor *descr;
 153        struct hfsplus_bheader_record *bnode;
 154        struct hfsplus_catalog_key *key;
 155        unsigned label_len;
 156        struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
 157        struct hfs_mdb *hfs;
 158        const uint8_t *buf;
 159
 160        dbg("probing at offset 0x%llx", (unsigned long long) off);
 161
 162        buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
 163        if (buf == NULL)
 164                return -1;
 165
 166        hfs = (struct hfs_mdb *) buf;
 167        if (hfs->signature[0] != 'B' || hfs->signature[1] != 'D')
 168                goto checkplus;
 169
 170        /* it may be just a hfs wrapper for hfs+ */
 171        if (hfs->embed_sig[0] == 'H' && hfs->embed_sig[1] == '+') {
 172                alloc_block_size = be32_to_cpu(hfs->al_blk_size);
 173                dbg("alloc_block_size 0x%x", alloc_block_size);
 174
 175                alloc_first_block = be16_to_cpu(hfs->al_bl_st);
 176                dbg("alloc_first_block 0x%x", alloc_first_block);
 177
 178                embed_first_block = be16_to_cpu(hfs->embed_startblock);
 179                dbg("embed_first_block 0x%x", embed_first_block);
 180
 181                off += (alloc_first_block * 512) +
 182                       (embed_first_block * alloc_block_size);
 183                dbg("hfs wrapped hfs+ found at offset 0x%llx", (unsigned long long) off);
 184
 185                buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
 186                if (buf == NULL)
 187                        return -1;
 188                goto checkplus;
 189        }
 190
 191        if (hfs->label_len > 0 && hfs->label_len < 28) {
 192//              volume_id_set_label_raw(id, hfs->label, hfs->label_len);
 193                volume_id_set_label_string(id, hfs->label, hfs->label_len) ;
 194        }
 195
 196        volume_id_set_uuid(id, hfs->finder_info.id, UUID_HFS);
 197//      volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
 198//      id->type = "hfs";
 199
 200        return 0;
 201
 202 checkplus:
 203        hfsplus = (struct hfsplus_vol_header *) buf;
 204        if (hfs->signature[0] == 'H')
 205                if (hfs->signature[1] == '+' || hfs->signature[1] == 'X')
 206                        goto hfsplus;
 207        return -1;
 208
 209 hfsplus:
 210        volume_id_set_uuid(id, hfsplus->finder_info.id, UUID_HFS);
 211
 212        blocksize = be32_to_cpu(hfsplus->blocksize);
 213        dbg("blocksize %u", blocksize);
 214
 215        memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
 216        cat_block = be32_to_cpu(extents[0].start_block);
 217        dbg("catalog start block 0x%x", cat_block);
 218
 219        buf = volume_id_get_buffer(id, off + (cat_block * blocksize), 0x2000);
 220        if (buf == NULL)
 221                goto found;
 222
 223        bnode = (struct hfsplus_bheader_record *)
 224                &buf[sizeof(struct hfsplus_bnode_descriptor)];
 225
 226        leaf_node_head = be32_to_cpu(bnode->leaf_head);
 227        dbg("catalog leaf node 0x%x", leaf_node_head);
 228
 229        leaf_node_size = be16_to_cpu(bnode->node_size);
 230        dbg("leaf node size 0x%x", leaf_node_size);
 231
 232        leaf_node_count = be32_to_cpu(bnode->leaf_count);
 233        dbg("leaf node count 0x%x", leaf_node_count);
 234        if (leaf_node_count == 0)
 235                goto found;
 236
 237        leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
 238
 239        /* get physical location */
 240        for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
 241                ext_block_start = be32_to_cpu(extents[ext].start_block);
 242                ext_block_count = be32_to_cpu(extents[ext].block_count);
 243                dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
 244
 245                if (ext_block_count == 0)
 246                        goto found;
 247
 248                /* this is our extent */
 249                if (leaf_block < ext_block_count)
 250                        break;
 251
 252                leaf_block -= ext_block_count;
 253        }
 254        if (ext == HFSPLUS_EXTENT_COUNT)
 255                goto found;
 256        dbg("found block in extent %i", ext);
 257
 258        leaf_off = (ext_block_start + leaf_block) * blocksize;
 259
 260        buf = volume_id_get_buffer(id, off + leaf_off, leaf_node_size);
 261        if (buf == NULL)
 262                goto found;
 263
 264        descr = (struct hfsplus_bnode_descriptor *) buf;
 265        dbg("descriptor type 0x%x", descr->type);
 266
 267        record_count = be16_to_cpu(descr->num_recs);
 268        dbg("number of records %u", record_count);
 269        if (record_count == 0)
 270                goto found;
 271
 272        if (descr->type != HFS_NODE_LEAF)
 273                goto found;
 274
 275        key = (struct hfsplus_catalog_key *)
 276                &buf[sizeof(struct hfsplus_bnode_descriptor)];
 277
 278        dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
 279        if (key->parent_id != cpu_to_be32(HFSPLUS_POR_CNID))
 280                goto found;
 281
 282        label_len = be16_to_cpu(key->unicode_len) * 2;
 283        dbg("label unicode16 len %i", label_len);
 284//      volume_id_set_label_raw(id, key->unicode, label_len);
 285        volume_id_set_label_unicode16(id, key->unicode, BE, label_len);
 286
 287 found:
 288//      volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
 289//      id->type = "hfsplus";
 290
 291        return 0;
 292}
 293