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