//
// hfs_misc.c - hfs routines
//
// Written by Eryk Vershen
//
/*
* Copyright 2000 by Eryk Vershen
*/
// for *printf()
#include <stdio.h>
// for malloc(), calloc() & free()
#ifndef __linux__
#include <stdlib.h>
#else
#include <malloc.h>
#endif
// for strncpy() & strcmp()
#include <string.h>
// for O_RDONLY & O_RDWR
#include <fcntl.h>
// for errno
#include <errno.h>
#include <inttypes.h>
#include "hfs_misc.h"
#include "partition_map.h"
#include "convert.h"
#include "errors.h"
//
// Defines
//
#define MDB_OFFSET 2
#define HFS_SIG 0x4244 /* i.e 'BD' */
#define HFS_PLUS_SIG 0x482B /* i.e 'H+' */
#define get_align_long(x) (*(uint32_t*)(x))
//
// Types
//
typedef long long u64;
typedef struct ExtDescriptor { // extent descriptor
uint16_t xdrStABN; // first allocation block
uint16_t xdrNumABlks; // number of allocation blocks
} ext_descriptor;
typedef struct ExtDataRec {
ext_descriptor ed[3]; // extent data record
} ext_data_rec;
/*
* The crazy "uint16_t x[2]" stuff here is to get around the fact
* that I can't convince the Mac compiler to align on 32 bit
* quantities on 16 bit boundaries...
*/
struct mdb_record { // master directory block
uint16_t drSigWord; // volume signature
uint16_t drCrDate[2]; // date and time of volume creation
uint16_t drLsMod[2]; // date and time of last modification
uint16_t drAtrb; // volume attributes
uint16_t drNmFls; // number of files in root directory
uint16_t drVBMSt; // first block of volume bitmap
uint16_t drAllocPtr; // start of next allocation search
uint16_t drNmAlBlks; // number of allocation blocks in volume
uint32_t drAlBlkSiz; // size (in bytes) of allocation blocks
uint32_t drClpSiz; // default clump size
uint16_t drAlBlSt; // first allocation block in volume
uint16_t drNxtCNID[2]; // next unused catalog node ID
uint16_t drFreeBks; // number of unused allocation blocks
char drVN[28]; // volume name
uint16_t drVolBkUp[2]; // date and time of last backup
uint16_t drVSeqNum; // volume backup sequence number
uint16_t drWrCnt[2]; // volume write count
uint16_t drXTClpSiz[2]; // clump size for extents overflow file
uint16_t drCTClpSiz[2]; // clump size for catalog file
uint16_t drNmRtDirs; // number of directories in root directory
uint32_t drFilCnt; // number of files in volume
uint32_t drDirCnt; // number of directories in volume
uint32_t drFndrInfo[8]; // information used by the Finder
#ifdef notdef
uint16_t drVCSize; // size (in blocks) of volume cache
uint16_t drVBMCSize; // size (in blocks) of volume bitmap cache
uint16_t drCtlCSize; // size (in blocks) of common volume cache
#else
uint16_t drEmbedSigWord; // type of embedded volume
ext_descriptor drEmbedExtent; // embedded volume extent
#endif
uint16_t drXTFlSize[2]; // size of extents overflow file
ext_data_rec drXTExtRec; // extent record for extents overflow file
uint16_t drCTFlSize[2]; // size of catalog file
ext_data_rec drCTExtRec; // extent record for catalog file
};
typedef uint32_t HFSCatalogNodeID;
typedef struct HFSPlusExtentDescriptor {
uint32_t startBlock;
uint32_t blockCount;
} HFSPlusExtentDescriptor;
typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[ 8];
typedef struct HFSPlusForkData {
u64 logicalSize;
uint32_t clumpSize;
uint32_t totalBlocks;
HFSPlusExtentRecord extents;
} HFSPlusForkData;
struct HFSPlusVolumeHeader {
uint16_t signature;
uint16_t version;
uint32_t attributes;
uint32_t lastMountedVersion;
uint32_t reserved;
uint32_t createDate;
uint32_t modifyDate;
uint32_t backupDate;
uint32_t checkedDate;
uint32_t fileCount;
uint32_t folderCount;
uint32_t blockSize;
uint32_t totalBlocks;
uint32_t freeBlocks;
uint32_t nextAllocation;
uint32_t rsrcClumpSize;
uint32_t dataClumpSize;
HFSCatalogNodeID nextCatalogID;
uint32_t writeCount;
u64 encodingsBitmap;
uint8_t finderInfo[ 32];
HFSPlusForkData allocationFile;
HFSPlusForkData extentsFile;
HFSPlusForkData catalogFile;
HFSPlusForkData attributesFile;
HFSPlusForkData startupFile;
} HFSPlusVolumeHeader;
//
// Global Constants
//
//
// Global Variables
//
//
// Forward declarations
//
uint32_t embeded_offset(struct mdb_record *mdb, uint32_t sector);
int read_partition_block(partition_map *entry, uint32_t num, char *buf);
//
// Routines
//
uint32_t
embeded_offset(struct mdb_record *mdb, uint32_t sector)
{
uint32_t e_offset;
e_offset = mdb->drAlBlSt + mdb->drEmbedExtent.xdrStABN * (mdb->drAlBlkSiz / 512);
return e_offset + sector;
}
char *
get_HFS_name(partition_map *entry, int *kind)
{
DPME *data;
struct mdb_record *mdb;
//struct HFSPlusVolumeHeader *mdb2;
char *name = NULL;
int len;
*kind = kHFS_not;
mdb = (struct mdb_record *) malloc(PBLOCK_SIZE);
if (mdb == NULL) {
error(errno, "can't allocate memory for MDB");
return NULL;
}
data = entry->data;
if (strcmp(data->dpme_type, kHFSType) == 0) {
if (read_partition_block(entry, 2, (char *)mdb) == 0) {
error(-1, "Can't read block %d from partition %d", 2, entry->disk_address);
goto not_hfs;
}
if (mdb->drSigWord == HFS_PLUS_SIG) {
// pure HFS Plus
// printf("%lu HFS Plus\n", entry->disk_address);
*kind = kHFS_plus;
} else if (mdb->drSigWord != HFS_SIG) {
// not HFS !!!
// printf("%"PRIu32" not HFS\n", entry->disk_address);
*kind = kHFS_not;
} else if (mdb->drEmbedSigWord != HFS_PLUS_SIG) {
// HFS
// printf("%lu HFS\n", entry->disk_address);
*kind = kHFS_std;
len = mdb->drVN[0];
name = (char *) malloc(len+1);
strncpy(name, &mdb->drVN[1], len);
name[len] = 0;
} else {
// embedded HFS plus
// printf("%lu embedded HFS Plus\n", entry->disk_address);
*kind = kHFS_embed;
len = mdb->drVN[0];
name = (char *) malloc(len+1);
strncpy(name, &mdb->drVN[1], len);
name[len] = 0;
}
}
not_hfs:
free(mdb);
return name;
}
// really need a function to read block n from partition m
int
read_partition_block(partition_map *entry, uint32_t num, char *buf)
{
DPME *data;
partition_map_header * map;
uint32_t base;
u64 offset;
map = entry->the_map;
data = entry->data;
base = data->dpme_pblock_start;
if (num >= data->dpme_pblocks) {
return 0;
}
offset = ((long long) base) * map->logical_block + num * 512;
return read_media(map->m, offset, 512, (void *)buf);
}