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
embeded_offset(struct mdb_record * mdb,uint32_t sector)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 *
get_HFS_name(partition_map * entry,int * kind)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
read_partition_block(partition_map * entry,uint32_t num,char * buf)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