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 "hfs_misc.h"
29#include "partition_map.h"
30#include "convert.h"
31#include "errors.h"
32
33
34//
35// Defines
36//
37#define MDB_OFFSET	2
38#define HFS_SIG		0x4244	/* i.e 'BD' */
39#define HFS_PLUS_SIG	0x482B	/* i.e 'H+' */
40
41#define get_align_long(x)	(*(u32*)(x))
42
43
44//
45// Types
46//
47typedef long long u64;
48
49typedef struct ExtDescriptor {		// extent descriptor
50    u16	xdrStABN;	// first allocation block
51    u16	xdrNumABlks;	// number of allocation blocks
52} ext_descriptor;
53
54typedef struct ExtDataRec {
55    ext_descriptor	ed[3];	// extent data record
56} ext_data_rec;
57
58/*
59 * The crazy "u16 x[2]" stuff here is to get around the fact
60 * that I can't convince the Mac compiler to align on 32 bit
61 * quantities on 16 bit boundaries...
62 */
63struct mdb_record {		// master directory block
64    u16	drSigWord;	// volume signature
65    u16	drCrDate[2];	// date and time of volume creation
66    u16	drLsMod[2];	// date and time of last modification
67    u16	drAtrb;		// volume attributes
68    u16	drNmFls;	// number of files in root directory
69    u16	drVBMSt;	// first block of volume bitmap
70    u16	drAllocPtr;	// start of next allocation search
71    u16	drNmAlBlks;	// number of allocation blocks in volume
72    u32	drAlBlkSiz;	// size (in bytes) of allocation blocks
73    u32	drClpSiz;	// default clump size
74    u16	drAlBlSt;	// first allocation block in volume
75    u16	drNxtCNID[2];	// next unused catalog node ID
76    u16	drFreeBks;	// number of unused allocation blocks
77    char	drVN[28];	// volume name
78    u16	drVolBkUp[2];	// date and time of last backup
79    u16	drVSeqNum;	// volume backup sequence number
80    u16	drWrCnt[2];	// volume write count
81    u16	drXTClpSiz[2];	// clump size for extents overflow file
82    u16	drCTClpSiz[2];	// clump size for catalog file
83    u16	drNmRtDirs;	// number of directories in root directory
84    u32	drFilCnt;	// number of files in volume
85    u32	drDirCnt;	// number of directories in volume
86    u32	drFndrInfo[8];	// information used by the Finder
87#ifdef notdef
88    u16	drVCSize;	// size (in blocks) of volume cache
89    u16	drVBMCSize;	// size (in blocks) of volume bitmap cache
90    u16	drCtlCSize;	// size (in blocks) of common volume cache
91#else
92    u16	drEmbedSigWord;	// type of embedded volume
93    ext_descriptor	drEmbedExtent;	// embedded volume extent
94#endif
95    u16	drXTFlSize[2];	// size of extents overflow file
96    ext_data_rec	drXTExtRec;	// extent record for extents overflow file
97    u16	drCTFlSize[2];	// size of catalog file
98    ext_data_rec	drCTExtRec;	// extent record for catalog file
99};
100
101
102typedef u32 HFSCatalogNodeID;
103
104typedef struct HFSPlusExtentDescriptor {
105    u32 startBlock;
106    u32 blockCount;
107} HFSPlusExtentDescriptor;
108
109typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[ 8];
110
111typedef struct HFSPlusForkData {
112    u64 logicalSize;
113    u32 clumpSize;
114    u32 totalBlocks;
115    HFSPlusExtentRecord extents;
116} HFSPlusForkData;
117
118struct HFSPlusVolumeHeader {
119    u16 signature;
120    u16 version;
121    u32 attributes;
122    u32 lastMountedVersion;
123    u32 reserved;
124    u32 createDate;
125    u32 modifyDate;
126    u32 backupDate;
127    u32 checkedDate;
128    u32 fileCount;
129    u32 folderCount;
130    u32 blockSize;
131    u32 totalBlocks;
132    u32 freeBlocks;
133    u32 nextAllocation;
134    u32 rsrcClumpSize;
135    u32 dataClumpSize;
136    HFSCatalogNodeID nextCatalogID;
137    u32 writeCount;
138    u64 encodingsBitmap;
139    u8 finderInfo[ 32];
140    HFSPlusForkData allocationFile;
141    HFSPlusForkData extentsFile;
142    HFSPlusForkData catalogFile;
143    HFSPlusForkData attributesFile;
144    HFSPlusForkData startupFile;
145} HFSPlusVolumeHeader;
146
147
148//
149// Global Constants
150//
151
152
153//
154// Global Variables
155//
156
157
158//
159// Forward declarations
160//
161u32 embeded_offset(struct mdb_record *mdb, u32 sector);
162int read_partition_block(partition_map *entry, unsigned long num, char *buf);
163
164
165//
166// Routines
167//
168u32
169embeded_offset(struct mdb_record *mdb, u32 sector)
170{
171    u32 e_offset;
172
173    e_offset = mdb->drAlBlSt + mdb->drEmbedExtent.xdrStABN * (mdb->drAlBlkSiz / 512);
174
175    return e_offset + sector;
176}
177
178
179char *
180get_HFS_name(partition_map *entry, int *kind)
181{
182    DPME *data;
183    struct mdb_record *mdb;
184    //struct HFSPlusVolumeHeader *mdb2;
185    char *name = NULL;
186    int len;
187
188    *kind = kHFS_not;
189
190    mdb = (struct mdb_record *) malloc(PBLOCK_SIZE);
191    if (mdb == NULL) {
192	error(errno, "can't allocate memory for MDB");
193	return NULL;
194    }
195
196    data = entry->data;
197    if (strcmp(data->dpme_type, kHFSType) == 0) {
198	if (read_partition_block(entry, 2, (char *)mdb) == 0) {
199	    error(-1, "Can't read block %d from partition %d", 2, entry->disk_address);
200	    goto not_hfs;
201	}
202	if (mdb->drSigWord == HFS_PLUS_SIG) {
203	    // pure HFS Plus
204	    // printf("%lu HFS Plus\n", entry->disk_address);
205	    *kind = kHFS_plus;
206	} else if (mdb->drSigWord != HFS_SIG) {
207	    // not HFS !!!
208	    // printf("%lu not HFS\n", entry->disk_address);
209	    *kind = kHFS_not;
210	} else if (mdb->drEmbedSigWord != HFS_PLUS_SIG) {
211	    // HFS
212	    // printf("%lu HFS\n", entry->disk_address);
213	    *kind = kHFS_std;
214	    len = mdb->drVN[0];
215	    name = (char *) malloc(len+1);
216	    strncpy(name, &mdb->drVN[1], len);
217	    name[len] = 0;
218	} else {
219	    // embedded HFS plus
220	    // printf("%lu embedded HFS Plus\n", entry->disk_address);
221	    *kind = kHFS_embed;
222	    len = mdb->drVN[0];
223	    name = (char *) malloc(len+1);
224	    strncpy(name, &mdb->drVN[1], len);
225	    name[len] = 0;
226	}
227    }
228not_hfs:
229    free(mdb);
230    return name;
231}
232
233// really need a function to read block n from partition m
234
235int
236read_partition_block(partition_map *entry, unsigned long num, char *buf)
237{
238    DPME *data;
239    partition_map_header * map;
240    u32 base;
241    u64 offset;
242
243    map = entry->the_map;
244    data = entry->data;
245    base = data->dpme_pblock_start;
246
247    if (num >= data->dpme_pblocks) {
248	return 0;
249    }
250    offset = ((long long) base) * map->logical_block + num * 512;
251
252    return read_media(map->m, offset, 512, (void *)buf);
253}
254