Home | History | Annotate | Line # | Download | only in dist
      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 //
     49 typedef long long u64;
     50 
     51 typedef struct ExtDescriptor {		// extent descriptor
     52     uint16_t	xdrStABN;	// first allocation block
     53     uint16_t	xdrNumABlks;	// number of allocation blocks
     54 } ext_descriptor;
     55 
     56 typedef 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  */
     65 struct 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 
    104 typedef uint32_t HFSCatalogNodeID;
    105 
    106 typedef struct HFSPlusExtentDescriptor {
    107     uint32_t startBlock;
    108     uint32_t blockCount;
    109 } HFSPlusExtentDescriptor;
    110 
    111 typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[ 8];
    112 
    113 typedef struct HFSPlusForkData {
    114     u64 logicalSize;
    115     uint32_t clumpSize;
    116     uint32_t totalBlocks;
    117     HFSPlusExtentRecord extents;
    118 } HFSPlusForkData;
    119 
    120 struct 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 //
    163 uint32_t embeded_offset(struct mdb_record *mdb, uint32_t sector);
    164 int read_partition_block(partition_map *entry, uint32_t num, char *buf);
    165 
    166 
    167 //
    168 // Routines
    169 //
    170 uint32_t
    171 embeded_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 
    181 char *
    182 get_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     }
    230 not_hfs:
    231     free(mdb);
    232     return name;
    233 }
    234 
    235 // really need a function to read block n from partition m
    236 
    237 int
    238 read_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