dist/pdisk/hfs_misc.c
author christos <christos@NetBSD.org>
Fri, 06 Apr 2012 22:41:47 +0000
branchtrunk
changeset 210445 c2e2044e951f
parent 101790 1f1d5d5e3d43
permissions -rw-r--r--
make this work on 64 bit machines; use stdint/inttypes.

//
// 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);
}