1// 2// hfs_misc.c - hfs routines 3// 4// Written by Eryk Vershen 5// 6 7/* 8 * Copyright 2000 by Eryk Vershen 9 */ 10 11// for *printf() 12#include <stdio.h> 13 14// for malloc(), calloc() & free() 15#ifndef __linux__ 16#include <stdlib.h> 17#else 18#include <malloc.h> 19#endif 20 21// for strncpy() & strcmp() 22#include <string.h> 23// for O_RDONLY & O_RDWR 24#include <fcntl.h> 25// for errno 26#include <errno.h> 27 28#include <inttypes.h> 29 30#include "hfs_misc.h" 31#include "partition_map.h" 32#include "convert.h" 33#include "errors.h" 34 35 36// 37// Defines 38// 39#define MDB_OFFSET 2 40#define HFS_SIG 0x4244 /* i.e 'BD' */ 41#define HFS_PLUS_SIG 0x482B /* i.e 'H+' */ 42 43#define get_align_long(x) (*(uint32_t*)(x)) 44 45 46// 47// Types 48// 49typedef long long u64; 50 51typedef struct ExtDescriptor { // extent descriptor 52 uint16_t xdrStABN; // first allocation block 53 uint16_t xdrNumABlks; // number of allocation blocks 54} ext_descriptor; 55 56typedef struct ExtDataRec { 57 ext_descriptor ed[3]; // extent data record 58} ext_data_rec; 59 60/* 61 * The crazy "uint16_t x[2]" stuff here is to get around the fact 62 * that I can't convince the Mac compiler to align on 32 bit 63 * quantities on 16 bit boundaries... 64 */ 65struct mdb_record { // master directory block 66 uint16_t drSigWord; // volume signature 67 uint16_t drCrDate[2]; // date and time of volume creation 68 uint16_t drLsMod[2]; // date and time of last modification 69 uint16_t drAtrb; // volume attributes 70 uint16_t drNmFls; // number of files in root directory 71 uint16_t drVBMSt; // first block of volume bitmap 72 uint16_t drAllocPtr; // start of next allocation search 73 uint16_t drNmAlBlks; // number of allocation blocks in volume 74 uint32_t drAlBlkSiz; // size (in bytes) of allocation blocks 75 uint32_t drClpSiz; // default clump size 76 uint16_t drAlBlSt; // first allocation block in volume 77 uint16_t drNxtCNID[2]; // next unused catalog node ID 78 uint16_t drFreeBks; // number of unused allocation blocks 79 char drVN[28]; // volume name 80 uint16_t drVolBkUp[2]; // date and time of last backup 81 uint16_t drVSeqNum; // volume backup sequence number 82 uint16_t drWrCnt[2]; // volume write count 83 uint16_t drXTClpSiz[2]; // clump size for extents overflow file 84 uint16_t drCTClpSiz[2]; // clump size for catalog file 85 uint16_t drNmRtDirs; // number of directories in root directory 86 uint32_t drFilCnt; // number of files in volume 87 uint32_t drDirCnt; // number of directories in volume 88 uint32_t drFndrInfo[8]; // information used by the Finder 89#ifdef notdef 90 uint16_t drVCSize; // size (in blocks) of volume cache 91 uint16_t drVBMCSize; // size (in blocks) of volume bitmap cache 92 uint16_t drCtlCSize; // size (in blocks) of common volume cache 93#else 94 uint16_t drEmbedSigWord; // type of embedded volume 95 ext_descriptor drEmbedExtent; // embedded volume extent 96#endif 97 uint16_t drXTFlSize[2]; // size of extents overflow file 98 ext_data_rec drXTExtRec; // extent record for extents overflow file 99 uint16_t drCTFlSize[2]; // size of catalog file 100 ext_data_rec drCTExtRec; // extent record for catalog file 101}; 102 103 104typedef uint32_t HFSCatalogNodeID; 105 106typedef struct HFSPlusExtentDescriptor { 107 uint32_t startBlock; 108 uint32_t blockCount; 109} HFSPlusExtentDescriptor; 110 111typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[ 8]; 112 113typedef struct HFSPlusForkData { 114 u64 logicalSize; 115 uint32_t clumpSize; 116 uint32_t totalBlocks; 117 HFSPlusExtentRecord extents; 118} HFSPlusForkData; 119 120struct HFSPlusVolumeHeader { 121 uint16_t signature; 122 uint16_t version; 123 uint32_t attributes; 124 uint32_t lastMountedVersion; 125 uint32_t reserved; 126 uint32_t createDate; 127 uint32_t modifyDate; 128 uint32_t backupDate; 129 uint32_t checkedDate; 130 uint32_t fileCount; 131 uint32_t folderCount; 132 uint32_t blockSize; 133 uint32_t totalBlocks; 134 uint32_t freeBlocks; 135 uint32_t nextAllocation; 136 uint32_t rsrcClumpSize; 137 uint32_t dataClumpSize; 138 HFSCatalogNodeID nextCatalogID; 139 uint32_t writeCount; 140 u64 encodingsBitmap; 141 uint8_t finderInfo[ 32]; 142 HFSPlusForkData allocationFile; 143 HFSPlusForkData extentsFile; 144 HFSPlusForkData catalogFile; 145 HFSPlusForkData attributesFile; 146 HFSPlusForkData startupFile; 147} HFSPlusVolumeHeader; 148 149 150// 151// Global Constants 152// 153 154 155// 156// Global Variables 157// 158 159 160// 161// Forward declarations 162// 163uint32_t embeded_offset(struct mdb_record *mdb, uint32_t sector); 164int read_partition_block(partition_map *entry, uint32_t num, char *buf); 165 166 167// 168// Routines 169// 170uint32_t 171embeded_offset(struct mdb_record *mdb, uint32_t sector) 172{ 173 uint32_t e_offset; 174 175 e_offset = mdb->drAlBlSt + mdb->drEmbedExtent.xdrStABN * (mdb->drAlBlkSiz / 512); 176 177 return e_offset + sector; 178} 179 180 181char * 182get_HFS_name(partition_map *entry, int *kind) 183{ 184 DPME *data; 185 struct mdb_record *mdb; 186 //struct HFSPlusVolumeHeader *mdb2; 187 char *name = NULL; 188 int len; 189 190 *kind = kHFS_not; 191 192 mdb = (struct mdb_record *) malloc(PBLOCK_SIZE); 193 if (mdb == NULL) { 194 error(errno, "can't allocate memory for MDB"); 195 return NULL; 196 } 197 198 data = entry->data; 199 if (strcmp(data->dpme_type, kHFSType) == 0) { 200 if (read_partition_block(entry, 2, (char *)mdb) == 0) { 201 error(-1, "Can't read block %d from partition %d", 2, entry->disk_address); 202 goto not_hfs; 203 } 204 if (mdb->drSigWord == HFS_PLUS_SIG) { 205 // pure HFS Plus 206 // printf("%lu HFS Plus\n", entry->disk_address); 207 *kind = kHFS_plus; 208 } else if (mdb->drSigWord != HFS_SIG) { 209 // not HFS !!! 210 // printf("%"PRIu32" not HFS\n", entry->disk_address); 211 *kind = kHFS_not; 212 } else if (mdb->drEmbedSigWord != HFS_PLUS_SIG) { 213 // HFS 214 // printf("%lu HFS\n", entry->disk_address); 215 *kind = kHFS_std; 216 len = mdb->drVN[0]; 217 name = (char *) malloc(len+1); 218 strncpy(name, &mdb->drVN[1], len); 219 name[len] = 0; 220 } else { 221 // embedded HFS plus 222 // printf("%lu embedded HFS Plus\n", entry->disk_address); 223 *kind = kHFS_embed; 224 len = mdb->drVN[0]; 225 name = (char *) malloc(len+1); 226 strncpy(name, &mdb->drVN[1], len); 227 name[len] = 0; 228 } 229 } 230not_hfs: 231 free(mdb); 232 return name; 233} 234 235// really need a function to read block n from partition m 236 237int 238read_partition_block(partition_map *entry, uint32_t num, char *buf) 239{ 240 DPME *data; 241 partition_map_header * map; 242 uint32_t base; 243 u64 offset; 244 245 map = entry->the_map; 246 data = entry->data; 247 base = data->dpme_pblock_start; 248 249 if (num >= data->dpme_pblocks) { 250 return 0; 251 } 252 offset = ((long long) base) * map->logical_block + num * 512; 253 254 return read_media(map->m, offset, 512, (void *)buf); 255} 256