254 lines
6.1 KiB
C
254 lines
6.1 KiB
C
//
|
|
// 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 "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) (*(u32*)(x))
|
|
|
|
|
|
//
|
|
// Types
|
|
//
|
|
typedef long long u64;
|
|
|
|
typedef struct ExtDescriptor { // extent descriptor
|
|
u16 xdrStABN; // first allocation block
|
|
u16 xdrNumABlks; // number of allocation blocks
|
|
} ext_descriptor;
|
|
|
|
typedef struct ExtDataRec {
|
|
ext_descriptor ed[3]; // extent data record
|
|
} ext_data_rec;
|
|
|
|
/*
|
|
* The crazy "u16 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
|
|
u16 drSigWord; // volume signature
|
|
u16 drCrDate[2]; // date and time of volume creation
|
|
u16 drLsMod[2]; // date and time of last modification
|
|
u16 drAtrb; // volume attributes
|
|
u16 drNmFls; // number of files in root directory
|
|
u16 drVBMSt; // first block of volume bitmap
|
|
u16 drAllocPtr; // start of next allocation search
|
|
u16 drNmAlBlks; // number of allocation blocks in volume
|
|
u32 drAlBlkSiz; // size (in bytes) of allocation blocks
|
|
u32 drClpSiz; // default clump size
|
|
u16 drAlBlSt; // first allocation block in volume
|
|
u16 drNxtCNID[2]; // next unused catalog node ID
|
|
u16 drFreeBks; // number of unused allocation blocks
|
|
char drVN[28]; // volume name
|
|
u16 drVolBkUp[2]; // date and time of last backup
|
|
u16 drVSeqNum; // volume backup sequence number
|
|
u16 drWrCnt[2]; // volume write count
|
|
u16 drXTClpSiz[2]; // clump size for extents overflow file
|
|
u16 drCTClpSiz[2]; // clump size for catalog file
|
|
u16 drNmRtDirs; // number of directories in root directory
|
|
u32 drFilCnt; // number of files in volume
|
|
u32 drDirCnt; // number of directories in volume
|
|
u32 drFndrInfo[8]; // information used by the Finder
|
|
#ifdef notdef
|
|
u16 drVCSize; // size (in blocks) of volume cache
|
|
u16 drVBMCSize; // size (in blocks) of volume bitmap cache
|
|
u16 drCtlCSize; // size (in blocks) of common volume cache
|
|
#else
|
|
u16 drEmbedSigWord; // type of embedded volume
|
|
ext_descriptor drEmbedExtent; // embedded volume extent
|
|
#endif
|
|
u16 drXTFlSize[2]; // size of extents overflow file
|
|
ext_data_rec drXTExtRec; // extent record for extents overflow file
|
|
u16 drCTFlSize[2]; // size of catalog file
|
|
ext_data_rec drCTExtRec; // extent record for catalog file
|
|
};
|
|
|
|
|
|
typedef u32 HFSCatalogNodeID;
|
|
|
|
typedef struct HFSPlusExtentDescriptor {
|
|
u32 startBlock;
|
|
u32 blockCount;
|
|
} HFSPlusExtentDescriptor;
|
|
|
|
typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[ 8];
|
|
|
|
typedef struct HFSPlusForkData {
|
|
u64 logicalSize;
|
|
u32 clumpSize;
|
|
u32 totalBlocks;
|
|
HFSPlusExtentRecord extents;
|
|
} HFSPlusForkData;
|
|
|
|
struct HFSPlusVolumeHeader {
|
|
u16 signature;
|
|
u16 version;
|
|
u32 attributes;
|
|
u32 lastMountedVersion;
|
|
u32 reserved;
|
|
u32 createDate;
|
|
u32 modifyDate;
|
|
u32 backupDate;
|
|
u32 checkedDate;
|
|
u32 fileCount;
|
|
u32 folderCount;
|
|
u32 blockSize;
|
|
u32 totalBlocks;
|
|
u32 freeBlocks;
|
|
u32 nextAllocation;
|
|
u32 rsrcClumpSize;
|
|
u32 dataClumpSize;
|
|
HFSCatalogNodeID nextCatalogID;
|
|
u32 writeCount;
|
|
u64 encodingsBitmap;
|
|
u8 finderInfo[ 32];
|
|
HFSPlusForkData allocationFile;
|
|
HFSPlusForkData extentsFile;
|
|
HFSPlusForkData catalogFile;
|
|
HFSPlusForkData attributesFile;
|
|
HFSPlusForkData startupFile;
|
|
} HFSPlusVolumeHeader;
|
|
|
|
|
|
//
|
|
// Global Constants
|
|
//
|
|
|
|
|
|
//
|
|
// Global Variables
|
|
//
|
|
|
|
|
|
//
|
|
// Forward declarations
|
|
//
|
|
u32 embeded_offset(struct mdb_record *mdb, u32 sector);
|
|
int read_partition_block(partition_map *entry, unsigned long num, char *buf);
|
|
|
|
|
|
//
|
|
// Routines
|
|
//
|
|
u32
|
|
embeded_offset(struct mdb_record *mdb, u32 sector)
|
|
{
|
|
u32 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("%lu 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, unsigned long num, char *buf)
|
|
{
|
|
DPME *data;
|
|
partition_map_header * map;
|
|
u32 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);
|
|
}
|