Root/
Source at commit HEAD created 5 years 6 days ago. By ifabio, Few update to kernelPatcher (Credits to CrazyBirdy) | |
---|---|
1 | /*␊ |
2 | * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.␊ |
3 | *␊ |
4 | * @APPLE_LICENSE_HEADER_START@␊ |
5 | *␊ |
6 | * The contents of this file constitute Original Code as defined in and␊ |
7 | * are subject to the Apple Public Source License Version 2.0 (the␊ |
8 | * "License"). You may not use this file except in compliance with the␊ |
9 | * License. Please obtain a copy of the License at␊ |
10 | * http://www.apple.com/publicsource and read it before using this file.␊ |
11 | * ␊ |
12 | * This Original Code and all software distributed under the License are␊ |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER␊ |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,␊ |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,␊ |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the␊ |
17 | * License for the specific language governing rights and limitations␊ |
18 | * under the License.␊ |
19 | *␊ |
20 | * @APPLE_LICENSE_HEADER_END@␊ |
21 | *␊ |
22 | *␊ |
23 | * hfs.c - File System Module for HFS and HFS+.␊ |
24 | *␊ |
25 | * Copyright (c) 1999-2002 Apple Computer, Inc.␊ |
26 | *␊ |
27 | * DRI: Josh de Cesare␊ |
28 | */␊ |
29 | ␊ |
30 | #include <sl.h>␊ |
31 | #include <hfs/hfs_format.h>␊ |
32 | ␊ |
33 | #include "hfs.h"␊ |
34 | ␊ |
35 | #define kBlockSize (0x200)␊ |
36 | ␊ |
37 | #define kMDBBaseOffset (2 * kBlockSize)␊ |
38 | ␊ |
39 | #define kBTreeCatalog (0)␊ |
40 | #define kBTreeExtents (1)␊ |
41 | ␊ |
42 | #ifdef __i386__␊ |
43 | ␊ |
44 | static CICell gCurrentIH;␊ |
45 | static long long gAllocationOffset;␊ |
46 | static long gIsHFSPlus;␊ |
47 | static long gCaseSensitive;␊ |
48 | static u_int32_t gBlockSize;␊ |
49 | static u_int32_t gCacheBlockSize;␊ |
50 | static char *gBTreeHeaderBuffer;␊ |
51 | static BTHeaderRec *gBTHeaders[2];␊ |
52 | static char *gHFSMdbVib;␊ |
53 | static HFSMasterDirectoryBlock *gHFSMDB;␊ |
54 | static char *gHFSPlusHeader;␊ |
55 | static HFSPlusVolumeHeader *gHFSPlus;␊ |
56 | static char *gLinkTemp;␊ |
57 | static long long gVolID;␊ |
58 | static char *gTempStr;␊ |
59 | ␊ |
60 | #else /* !__i386__ */␊ |
61 | ␊ |
62 | static CICell␉␉␉gCurrentIH;␊ |
63 | static long long␉␉gAllocationOffset;␊ |
64 | static long␉␉␉gIsHFSPlus;␊ |
65 | static long␉␉␉gCaseSensitive;␊ |
66 | static u_int32_t␉␉gBlockSize;␊ |
67 | static u_int32_t␉␉gCacheBlockSize;␊ |
68 | static char␉␉␉gBTreeHeaderBuffer[512];␊ |
69 | static BTHeaderRec␉␉*gBTHeaders[2];␊ |
70 | static char␉␉␉gHFSMdbVib[kBlockSize];␊ |
71 | static HFSMasterDirectoryBlock␉*gHFSMDB =(HFSMasterDirectoryBlock*)gHFSMdbVib;␊ |
72 | static char␉␉␉gHFSPlusHeader[kBlockSize];␊ |
73 | static HFSPlusVolumeHeader␉*gHFSPlus =(HFSPlusVolumeHeader*)gHFSPlusHeader;␊ |
74 | static char␉␉␉gLinkTemp[64];␊ |
75 | static long long␉␉gVolID;␊ |
76 | ␊ |
77 | #endif /* !__i386__ */␊ |
78 | ␊ |
79 | static long ReadFile(void *file, u_int64_t *length, void *base, u_int64_t offset);␊ |
80 | static long GetCatalogEntryInfo(void *entry, long *flags, u_int32_t *time,␊ |
81 | FinderInfo *finderInfo, long *infoValid);␊ |
82 | static long ResolvePathToCatalogEntry(char *filePath, long *flags,␊ |
83 | void *entry, u_int32_t dirID, long long *dirIndex);␊ |
84 | ␊ |
85 | static long GetCatalogEntry(long long *dirIndex, char **name,␊ |
86 | long *flags, u_int32_t *time,␊ |
87 | FinderInfo *finderInfo, long *infoValid);␊ |
88 | static long ReadCatalogEntry(char *fileName, u_int32_t dirID, void *entry,␊ |
89 | long long *dirIndex);␊ |
90 | static long ReadExtentsEntry(u_int32_t fileID, long startBlock, void *entry);␊ |
91 | ␊ |
92 | static long ReadBTreeEntry(long btree, void *key, char *entry, long long *dirIndex);␊ |
93 | static void GetBTreeRecord(u_int16_t index, char *nodeBuffer, u_int16_t nodeSize,␊ |
94 | char **key, char **data);␊ |
95 | ␊ |
96 | static long ReadExtent(char *extent, u_int64_t extentSize, u_int32_t extentFile,␊ |
97 | u_int64_t offset, u_int64_t size, void *buffer, long cache);␊ |
98 | ␊ |
99 | static u_int32_t GetExtentStart(void *extents, u_int32_t index);␊ |
100 | static u_int32_t GetExtentSize(void *extents, u_int32_t index);␊ |
101 | ␊ |
102 | static long CompareHFSCatalogKeys(void *key, void *testKey);␊ |
103 | static long CompareHFSPlusCatalogKeys(void *key, void *testKey);␊ |
104 | static long CompareHFSExtentsKeys(void *key, void *testKey);␊ |
105 | static long CompareHFSPlusExtentsKeys(void *key, void *testKey);␊ |
106 | ␊ |
107 | extern long FastRelString(u_int8_t *str1, u_int8_t *str2);␊ |
108 | extern long BinaryUnicodeCompare(u_int16_t *uniStr1, u_int32_t len1, u_int16_t *uniStr2, u_int32_t len2);␊ |
109 | ␊ |
110 | ␊ |
111 | //==============================================================================␊ |
112 | ␊ |
113 | static void SwapFinderInfo(FndrFileInfo *dst, FndrFileInfo *src)␊ |
114 | {␊ |
115 | ␉dst->fdType = SWAP_BE32(src->fdType);␊ |
116 | ␉dst->fdCreator = SWAP_BE32(src->fdCreator);␊ |
117 | ␉dst->fdFlags = SWAP_BE16(src->fdFlags);␊ |
118 | ␉// Don't bother with location␊ |
119 | }␊ |
120 | ␊ |
121 | //==============================================================================␊ |
122 | ␊ |
123 | void HFSFree(CICell ih)␊ |
124 | {␊ |
125 | ␉if(gCurrentIH == ih)␊ |
126 | ␉{␊ |
127 | ␉␉gCurrentIH = 0;␊ |
128 | ␉}␊ |
129 | ␉free(ih);␊ |
130 | }␊ |
131 | ␊ |
132 | //==============================================================================␊ |
133 | ␊ |
134 | bool HFSProbe (const void *buf)␊ |
135 | {␊ |
136 | ␉const HFSMasterDirectoryBlock *mdb = (const HFSMasterDirectoryBlock *)(((const char*)buf)+kMDBBaseOffset);␊ |
137 | ␉const HFSPlusVolumeHeader *header = (const HFSPlusVolumeHeader *)(((const char*)buf)+kMDBBaseOffset);␊ |
138 | ␉␊ |
139 | ␉if ( SWAP_BE16(mdb->drSigWord) == kHFSSigWord )␊ |
140 | ␉{␊ |
141 | ␉␉return true;␊ |
142 | ␉}␊ |
143 | ␊ |
144 | ␉if (SWAP_BE16(header->signature) != kHFSPlusSigWord && SWAP_BE16(header->signature) != kHFSXSigWord) {␊ |
145 | ␉␉return false;␊ |
146 | ␉}␊ |
147 | ␉return true;␊ |
148 | }␊ |
149 | ␊ |
150 | //==============================================================================␊ |
151 | ␊ |
152 | long HFSInitPartition(CICell ih)␊ |
153 | {␊ |
154 | ␉u_int64_t extentSize;␊ |
155 | ␉void *extent;␊ |
156 | ␉u_int32_t extentFile;␊ |
157 | ␉u_int16_t nodeSize;␊ |
158 | ␊ |
159 | ␉if (ih == gCurrentIH)␊ |
160 | ␉{␊ |
161 | #ifdef __i386__␊ |
162 | ␉␉CacheInit(ih, gCacheBlockSize);␊ |
163 | #endif␊ |
164 | ␉return 0L;␊ |
165 | ␉}␊ |
166 | ␊ |
167 | #ifdef __i386__␊ |
168 | ␉if (!gTempStr)␊ |
169 | ␉{␊ |
170 | ␉␉gTempStr = (char *)malloc(4096);␊ |
171 | ␉}␊ |
172 | ␊ |
173 | ␉if (!gLinkTemp)␊ |
174 | ␉{␊ |
175 | ␉␉gLinkTemp = (char *)malloc(64);␊ |
176 | ␉}␊ |
177 | ␊ |
178 | ␉if (!gBTreeHeaderBuffer)␊ |
179 | ␉{␊ |
180 | ␉␉gBTreeHeaderBuffer = (char *)malloc(512);␊ |
181 | ␉}␊ |
182 | ␊ |
183 | ␉if (!gHFSMdbVib)␊ |
184 | ␉{␊ |
185 | ␉␉gHFSMdbVib = (char *)malloc(kBlockSize);␊ |
186 | ␉␉gHFSMDB = (HFSMasterDirectoryBlock *)gHFSMdbVib;␊ |
187 | ␉}␊ |
188 | ␊ |
189 | ␉if (!gHFSPlusHeader)␊ |
190 | ␉{␊ |
191 | ␉␉gHFSPlusHeader = (char *)malloc(kBlockSize);␊ |
192 | ␉␉gHFSPlus = (HFSPlusVolumeHeader *)gHFSPlusHeader;␊ |
193 | ␉}␊ |
194 | ␊ |
195 | ␉if (!gTempStr || !gLinkTemp || !gBTreeHeaderBuffer || !gHFSMdbVib || !gHFSPlusHeader)␊ |
196 | ␉{␊ |
197 | ␉␉return -1;␊ |
198 | ␉}␊ |
199 | #endif /* __i386__ */␊ |
200 | ␊ |
201 | ␉gAllocationOffset = 0;␊ |
202 | ␉gIsHFSPlus = 0;␊ |
203 | ␉gCaseSensitive = 0;␊ |
204 | ␉gBTHeaders[0] = 0;␊ |
205 | ␉gBTHeaders[1] = 0;␊ |
206 | ␊ |
207 | ␉// Look for the HFS MDB␊ |
208 | ␉Seek(ih, kMDBBaseOffset);␊ |
209 | ␉Read(ih, (long)gHFSMdbVib, kBlockSize);␊ |
210 | ␊ |
211 | ␉if (SWAP_BE16(gHFSMDB->drSigWord) == kHFSSigWord)␊ |
212 | ␉{␊ |
213 | ␉␉gAllocationOffset = SWAP_BE16(gHFSMDB->drAlBlSt) * kBlockSize;␊ |
214 | ␊ |
215 | ␉␉// See if it is HFSPlus␊ |
216 | ␉␉if (SWAP_BE16(gHFSMDB->drEmbedSigWord) != kHFSPlusSigWord)␊ |
217 | ␉␉{␊ |
218 | ␉␉␉// Normal HFS;␊ |
219 | ␉␉␉gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSMDB->drAlBlkSiz);␊ |
220 | ␉␉␉CacheInit(ih, gCacheBlockSize);␊ |
221 | ␉␉␉gCurrentIH = ih;␊ |
222 | ␊ |
223 | ␉␉␉// grab the 64 bit volume ID␊ |
224 | ␉␉␉bcopy(&gHFSMDB->drFndrInfo[6], &gVolID, 8);␊ |
225 | ␊ |
226 | ␉␉␉// Get the Catalog BTree node size.␊ |
227 | ␉␉␉extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;␊ |
228 | ␉␉␉extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);␊ |
229 | ␉␉␉extentFile = kHFSCatalogFileID;␊ |
230 | ␉␉␉ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + kBTreeCatalog * 256, 0);␊ |
231 | ␊ |
232 | ␉␉␉nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + sizeof(BTNodeDescriptor)))->nodeSize);␊ |
233 | ␊ |
234 | ␉␉␉// If the BTree node size is larger than the block size, reset the cache.␊ |
235 | ␉␉␉if (nodeSize > gBlockSize)␊ |
236 | ␉␉␉{␊ |
237 | ␉␉␉␉gCacheBlockSize = nodeSize;␊ |
238 | ␉␉␉␉CacheInit(ih, gCacheBlockSize);␊ |
239 | ␉␉␉}␊ |
240 | ␊ |
241 | ␉␉return 0;␊ |
242 | ␉␉}␊ |
243 | ␊ |
244 | ␉␉// Calculate the offset to the embeded HFSPlus volume.␊ |
245 | ␉␉gAllocationOffset += (long long)SWAP_BE16(gHFSMDB->drEmbedExtent.startBlock) *␊ |
246 | SWAP_BE32(gHFSMDB->drAlBlkSiz);␊ |
247 | ␉}␊ |
248 | ␊ |
249 | ␉// Look for the HFSPlus Header␊ |
250 | ␉Seek(ih, gAllocationOffset + kMDBBaseOffset);␊ |
251 | ␉Read(ih, (long)gHFSPlusHeader, kBlockSize);␊ |
252 | ␊ |
253 | ␉// Not a HFS+ or HFSX volume.␊ |
254 | ␉if (SWAP_BE16(gHFSPlus->signature) != kHFSPlusSigWord && SWAP_BE16(gHFSPlus->signature) != kHFSXSigWord)␊ |
255 | ␉{␊ |
256 | ␉␉verbose("HFS signature was not present.\n");␊ |
257 | ␉␉gCurrentIH = 0;␊ |
258 | ␊ |
259 | ␉␉return -1L;␊ |
260 | ␉}␊ |
261 | ␊ |
262 | ␉gIsHFSPlus = 1;␊ |
263 | ␉gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSPlus->blockSize);␊ |
264 | ␉CacheInit(ih, gCacheBlockSize);␊ |
265 | ␉gCurrentIH = ih;␊ |
266 | ␊ |
267 | ␉ih->modTime = SWAP_BE32(gHFSPlus->modifyDate) - 2082844800;␊ |
268 | ␊ |
269 | ␉// grab the 64 bit volume ID␊ |
270 | ␉bcopy(&gHFSPlus->finderInfo[24], &gVolID, 8);␊ |
271 | ␊ |
272 | ␉// Get the Catalog BTree node size.␊ |
273 | ␉extent = &gHFSPlus->catalogFile.extents;␊ |
274 | ␉extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);␊ |
275 | ␉extentFile = kHFSCatalogFileID;␊ |
276 | ␊ |
277 | ␉ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + kBTreeCatalog * 256, 0);␊ |
278 | ␊ |
279 | ␉nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + sizeof(BTNodeDescriptor)))->nodeSize);␊ |
280 | ␊ |
281 | ␉// If the BTree node size is larger than the block size, reset the cache.␊ |
282 | ␉if (nodeSize > gBlockSize)␊ |
283 | ␉{␊ |
284 | ␉␉gCacheBlockSize = nodeSize;␊ |
285 | ␉␉CacheInit(ih, gCacheBlockSize);␊ |
286 | ␉}␊ |
287 | ␊ |
288 | ␉return 0L;␊ |
289 | }␊ |
290 | ␊ |
291 | //==============================================================================␊ |
292 | ␊ |
293 | long HFSLoadFile(CICell ih, char * filePath)␊ |
294 | {␊ |
295 | ␉return HFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);␊ |
296 | }␊ |
297 | ␊ |
298 | long HFSReadFile(CICell ih, char *filePath, void *base, u_int64_t offset, u_int64_t length)␊ |
299 | {␊ |
300 | ␉char entry[512];␊ |
301 | ␉char devStr[12];␊ |
302 | ␉u_int32_t dirID;␊ |
303 | ␉long result, flags = 0;␊ |
304 | ␊ |
305 | ␉if (HFSInitPartition(ih) == -1)␊ |
306 | ␉{␊ |
307 | ␉␉return -1;␊ |
308 | ␉}␊ |
309 | ␊ |
310 | ␉dirID = kHFSRootFolderID;␊ |
311 | ␉// Skip a lead '/'. Start in the system folder if there are two.␊ |
312 | ␉if (filePath[0] == '/')␊ |
313 | ␉{␊ |
314 | ␉␉if (filePath[1] == '/')␊ |
315 | ␉␉{␊ |
316 | ␉␉␉if (gIsHFSPlus)␊ |
317 | ␉␉␉{␊ |
318 | ␉␉␉␉dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);␊ |
319 | ␉␉␉}␊ |
320 | ␉␉␉else␊ |
321 | ␉␉␉{␊ |
322 | ␉␉␉␉dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);␊ |
323 | ␉␉␉}␊ |
324 | ␊ |
325 | ␉␉␉if (dirID == 0)␊ |
326 | ␉␉␉{␊ |
327 | ␉␉␉␉return -1L;␊ |
328 | ␉␉␉}␊ |
329 | ␊ |
330 | ␉␉␉filePath++;␊ |
331 | ␉␉}␊ |
332 | ␊ |
333 | ␉␉filePath++;␊ |
334 | ␉}␊ |
335 | ␊ |
336 | ␉result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);␊ |
337 | ␊ |
338 | ␉if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))␊ |
339 | ␉{␊ |
340 | ␉␉return -1L;␊ |
341 | ␉}␊ |
342 | ␊ |
343 | #if UNUSED␊ |
344 | ␉// Not yet for Intel. System.config/Default.table will fail this check.␊ |
345 | ␉// Check file owner and permissions.␊ |
346 | ␉if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite))␊ |
347 | ␉{␊ |
348 | ␉␉return -1L;␊ |
349 | ␉}␊ |
350 | #endif␊ |
351 | ␊ |
352 | ␉result = ReadFile(entry, &length, base, offset);␊ |
353 | ␉if (result == -1)␊ |
354 | ␉{␊ |
355 | ␉␉return -1L;␊ |
356 | ␉}␊ |
357 | ␊ |
358 | ␉getDeviceDescription(ih, devStr);␊ |
359 | ␊ |
360 | ␉verbose("Read HFS%s file: [%s/%s] %d bytes.\n",␉(gIsHFSPlus ? "+" : ""), devStr, filePath, (uint32_t)length);␊ |
361 | ␊ |
362 | ␉return length;␊ |
363 | }␊ |
364 | ␊ |
365 | long HFSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex, char ** name, long * flags, u_int32_t * time, FinderInfo * finderInfo, long * infoValid)␊ |
366 | {␊ |
367 | ␉char entry[512];␊ |
368 | ␉u_int32_t dirID;␊ |
369 | ␉long dirFlags;␊ |
370 | ␊ |
371 | ␉if (HFSInitPartition(ih) == -1)␊ |
372 | ␉{␊ |
373 | ␉␉return -1;␊ |
374 | ␉}␊ |
375 | ␊ |
376 | ␉if (*dirIndex == -1)␊ |
377 | ␉{␊ |
378 | ␉␉return -1;␊ |
379 | ␉}␊ |
380 | ␊ |
381 | ␉dirID = kHFSRootFolderID;␊ |
382 | ␊ |
383 | ␉// Skip a lead '/'. Start in the system folder if there are two.␊ |
384 | ␉if (dirPath[0] == '/')␊ |
385 | ␉{␊ |
386 | ␉␉if (dirPath[1] == '/')␊ |
387 | ␉␉{␊ |
388 | ␉␉␉if (gIsHFSPlus)␊ |
389 | ␉␉␉{␊ |
390 | ␉␉␉␉dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);␊ |
391 | ␉␉␉}␊ |
392 | ␉␉␉else␊ |
393 | ␉␉␉{␊ |
394 | ␉␉␉␉dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);␊ |
395 | ␉␉␉}␊ |
396 | ␊ |
397 | ␉␉␉if (dirID == 0)␊ |
398 | ␉␉␉{␊ |
399 | ␉␉␉␉return -1;␊ |
400 | ␉␉␉}␊ |
401 | ␊ |
402 | ␉␉␉dirPath++;␊ |
403 | ␉␉}␊ |
404 | ␊ |
405 | ␉␉dirPath++;␊ |
406 | ␉}␊ |
407 | ␊ |
408 | ␉if (*dirIndex == 0)␊ |
409 | ␉{␊ |
410 | ␉␉ResolvePathToCatalogEntry(dirPath, &dirFlags, entry, dirID, dirIndex);␊ |
411 | ␊ |
412 | ␉␉if (*dirIndex == 0)␊ |
413 | ␉␉{␊ |
414 | ␉␉␉*dirIndex = -1;␊ |
415 | ␉␉}␊ |
416 | ␊ |
417 | ␉␉if ((dirFlags & kFileTypeMask) != kFileTypeUnknown)␊ |
418 | ␉␉{␊ |
419 | ␉␉␉return -1;␊ |
420 | ␉␉}␊ |
421 | ␉}␊ |
422 | ␊ |
423 | ␉GetCatalogEntry(dirIndex, name, flags, time, finderInfo, infoValid);␊ |
424 | ␊ |
425 | ␉if (*dirIndex == 0)␊ |
426 | ␉{␊ |
427 | ␉␉*dirIndex = -1;␊ |
428 | ␉}␊ |
429 | ␊ |
430 | ␉if ((*flags & kFileTypeMask) == kFileTypeUnknown)␊ |
431 | ␉{␊ |
432 | ␉␉return -1;␊ |
433 | ␉}␊ |
434 | ␊ |
435 | ␉return 0;␊ |
436 | }␊ |
437 | ␊ |
438 | //==============================================================================␊ |
439 | ␊ |
440 | void HFSGetDescription(CICell ih, char *str, long strMaxLen)␊ |
441 | {␊ |
442 | ␉long long dirIndex = 0;␊ |
443 | ␉char *name;␊ |
444 | ␉long flags;␊ |
445 | ␉u_int32_t firstLeafNode;␊ |
446 | ␉u_int32_t time;␊ |
447 | ␉u_int16_t nodeSize;␊ |
448 | ␊ |
449 | ␉if (HFSInitPartition(ih) == -1)␊ |
450 | ␉{␊ |
451 | ␉␉return;␊ |
452 | ␉}␊ |
453 | ␊ |
454 | ␉/* Fill some crucial data structures by side effect. */␊ |
455 | ␉HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);␊ |
456 | ␊ |
457 | ␉/* Now we can loook up the volume name node. */␊ |
458 | ␉nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);␊ |
459 | ␉firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);␊ |
460 | ␊ |
461 | ␉dirIndex = (long long)firstLeafNode * nodeSize;␊ |
462 | ␊ |
463 | ␉GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);␊ |
464 | ␊ |
465 | ␉strncpy(str, name, strMaxLen);␊ |
466 | ␉str[strMaxLen] = '\0';␊ |
467 | }␊ |
468 | ␊ |
469 | //==============================================================================␊ |
470 | ␊ |
471 | long HFSGetFileBlock(CICell ih, char *filePath, u_int64_t *firstBlock)␊ |
472 | {␊ |
473 | ␉char entry[512];␊ |
474 | ␉long result, flags;␊ |
475 | ␉u_int32_t dirID;␊ |
476 | ␉void *extents;␊ |
477 | ␊ |
478 | ␉HFSCatalogFile *hfsFile = (void *)entry;␊ |
479 | ␉HFSPlusCatalogFile *hfsPlusFile = (void *)entry;␊ |
480 | ␊ |
481 | ␉if (HFSInitPartition(ih) == -1)␊ |
482 | ␉{␊ |
483 | ␉␉return -1L;␊ |
484 | ␉}␊ |
485 | ␊ |
486 | ␉dirID = kHFSRootFolderID;␊ |
487 | ␉// Skip a lead '/'. Start in the system folder if there are two.␊ |
488 | ␉if (filePath[0] == '/')␊ |
489 | ␉{␊ |
490 | ␉␉if (filePath[1] == '/')␊ |
491 | ␉␉{␊ |
492 | ␉␉␉if (gIsHFSPlus)␊ |
493 | ␉␉␉{␊ |
494 | ␉␉␉␉dirID = SWAP_BE32(((long *) gHFSPlus->finderInfo)[5]);␊ |
495 | ␉␉␉}␊ |
496 | ␉␉␉else␊ |
497 | ␉␉␉{␊ |
498 | ␉␉␉␉dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);␊ |
499 | ␉␉␉}␊ |
500 | ␊ |
501 | ␉␉␉if (dirID == 0)␊ |
502 | ␉␉␉{␊ |
503 | ␉␉␉␉return -1;␊ |
504 | ␉␉␉}␊ |
505 | ␉␉␉filePath++;␊ |
506 | ␉␉}␊ |
507 | ␉␉filePath++;␊ |
508 | ␉}␊ |
509 | ␊ |
510 | ␉result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);␊ |
511 | ␊ |
512 | ␉if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))␊ |
513 | ␉{␊ |
514 | ␉␉printf("HFS: Resolve path '%s' failed\n", filePath);␊ |
515 | ␉␉return -1L;␊ |
516 | ␉}␊ |
517 | ␊ |
518 | ␉if (gIsHFSPlus)␊ |
519 | ␉{␊ |
520 | ␉␉extents = &hfsPlusFile->dataFork.extents;␊ |
521 | ␉}␊ |
522 | ␉else␊ |
523 | ␉{␊ |
524 | ␉␉extents = &hfsFile->dataExtents;␊ |
525 | ␉}␊ |
526 | ␊ |
527 | #if DEBUG␊ |
528 | ␉printf("extent start 0x%x\n", GetExtentStart(extents, 0));␊ |
529 | ␉printf("block size 0x%x\n", gBlockSize);␊ |
530 | ␉printf("Allocation offset 0x%x\n", (unsigned long)gAllocationOffset);␊ |
531 | #endif␊ |
532 | ␉*firstBlock = ((u_int64_t) GetExtentStart(extents, 0) * (u_int64_t) gBlockSize + gAllocationOffset) / 512ULL;␊ |
533 | ␉return 0L;␊ |
534 | }␊ |
535 | ␊ |
536 | ␊ |
537 | //==============================================================================␊ |
538 | ␊ |
539 | long HFSGetUUID(CICell ih, char *uuidStr)␊ |
540 | {␊ |
541 | ␉if (HFSInitPartition(ih) == -1)␊ |
542 | ␉{␊ |
543 | ␉␉return -1;␊ |
544 | ␉}␊ |
545 | ␊ |
546 | ␉if (gVolID == 0LL)␊ |
547 | ␉{␊ |
548 | ␉␉return -1;␊ |
549 | ␉}␊ |
550 | ␊ |
551 | ␉return CreateUUIDString((uint8_t*)(&gVolID), sizeof(gVolID), uuidStr);␊ |
552 | }␊ |
553 | ␊ |
554 | //==============================================================================␊ |
555 | // Private Functions␊ |
556 | ␊ |
557 | static long ReadFile(void * file, u_int64_t * length, void * base, u_int64_t offset)␊ |
558 | {␊ |
559 | ␉u_int64_t fileLength;␊ |
560 | ␉void *extents;␊ |
561 | ␉HFSCatalogFile *hfsFile = file;␊ |
562 | ␉HFSPlusCatalogFile *hfsPlusFile = file;␊ |
563 | ␉u_int32_t fileID;␊ |
564 | ␊ |
565 | ␉if (gIsHFSPlus)␊ |
566 | ␉{␊ |
567 | ␉␉fileID = SWAP_BE32(hfsPlusFile->fileID);␊ |
568 | ␉␉fileLength = (uint64_t)SWAP_BE64(hfsPlusFile->dataFork.logicalSize);␊ |
569 | ␉␉extents = &hfsPlusFile->dataFork.extents;␊ |
570 | ␉}␊ |
571 | ␉else␊ |
572 | ␉{␊ |
573 | ␉␉fileID = SWAP_BE32(hfsFile->fileID);␊ |
574 | ␉␉fileLength = SWAP_BE32(hfsFile->dataLogicalSize);␊ |
575 | ␉␉extents = &hfsFile->dataExtents;␊ |
576 | ␉}␊ |
577 | ␊ |
578 | ␉if (offset > fileLength)␊ |
579 | ␉{␊ |
580 | ␉␉printf("ReadFile(HFS%s): Offset is too large.\n", gIsHFSPlus ? "+" : "");␊ |
581 | ␊ |
582 | ␉␉return -1L;␊ |
583 | ␉}␊ |
584 | ␊ |
585 | ␉if ((*length == 0) || ((offset + *length) > fileLength))␊ |
586 | ␉{␊ |
587 | ␉␉*length = fileLength - offset;␊ |
588 | ␉}␊ |
589 | ␊ |
590 | /*␊ |
591 | ␉if (*length > kLoadSize)␊ |
592 | ␉{␊ |
593 | ␉␉printf("File is too large.\n");␊ |
594 | ␉␉return -1;␊ |
595 | ␉}␊ |
596 | */␊ |
597 | ␊ |
598 | ␉*length = ReadExtent((char *)extents, fileLength, fileID, offset, *length, (char *)base, 0);␊ |
599 | ␊ |
600 | ␉return 0L;␊ |
601 | }␊ |
602 | ␊ |
603 | //==============================================================================␊ |
604 | ␊ |
605 | static long GetCatalogEntryInfo(void * entry, long * flags, u_int32_t * time, FinderInfo * finderInfo, long * infoValid)␊ |
606 | {␊ |
607 | ␉u_int32_t tmpTime = 0L;␊ |
608 | ␉long valid = 0L;␊ |
609 | ␊ |
610 | ␉// Get information about the file.␊ |
611 | ␊ |
612 | ␉switch ( SWAP_BE16(*(short *)entry) )␊ |
613 | ␉{␊ |
614 | ␉case kHFSFolderRecord :␊ |
615 | ␉␉*flags = kFileTypeDirectory;␊ |
616 | ␉␉tmpTime = SWAP_BE32(((HFSCatalogFolder *)entry)->modifyDate);␊ |
617 | ␉␉break;␊ |
618 | ␊ |
619 | ␉case kHFSPlusFolderRecord :␊ |
620 | ␉␉*flags = kFileTypeDirectory | (SWAP_BE16(((HFSPlusCatalogFolder *)entry)->bsdInfo.fileMode) & kPermMask);␊ |
621 | ␊ |
622 | ␉␉if (SWAP_BE32(((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID) != 0)␊ |
623 | ␉␉{␊ |
624 | ␉␉␉*flags |= kOwnerNotRoot;␊ |
625 | ␉␉}␊ |
626 | ␉␉tmpTime = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->contentModDate);␊ |
627 | ␉␉break;␊ |
628 | ␊ |
629 | ␉case kHFSFileRecord :␊ |
630 | ␉␉*flags = kFileTypeFlat;␊ |
631 | ␉␉tmpTime = SWAP_BE32(((HFSCatalogFile *)entry)->modifyDate);␊ |
632 | ␉␉if (finderInfo)␊ |
633 | ␉␉{␊ |
634 | ␉␉␉SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSCatalogFile *)entry)->userInfo);␊ |
635 | ␉␉␉valid = 1;␊ |
636 | ␉␉}␊ |
637 | ␉␉break;␊ |
638 | ␊ |
639 | ␉case kHFSPlusFileRecord :␊ |
640 | ␉␉*flags = kFileTypeFlat | (SWAP_BE16(((HFSPlusCatalogFile *)entry)->bsdInfo.fileMode) & kPermMask);␊ |
641 | ␉␉if (SWAP_BE32(((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID) != 0)␊ |
642 | ␉␉{␊ |
643 | ␉␉␉*flags |= kOwnerNotRoot;␊ |
644 | ␉␉}␊ |
645 | ␉␉tmpTime = SWAP_BE32(((HFSPlusCatalogFile *)entry)->contentModDate);␊ |
646 | ␉␉if (finderInfo)␊ |
647 | ␉␉{␊ |
648 | ␉␉␉SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSPlusCatalogFile *)entry)->userInfo);␊ |
649 | ␉␉␉valid = 1;␊ |
650 | ␉␉}␊ |
651 | ␉␉break;␊ |
652 | ␊ |
653 | ␉case kHFSFileThreadRecord :␊ |
654 | ␉case kHFSPlusFileThreadRecord :␊ |
655 | ␉case kHFSFolderThreadRecord :␊ |
656 | ␉case kHFSPlusFolderThreadRecord :␊ |
657 | ␉␉*flags = kFileTypeUnknown;␊ |
658 | ␉␉tmpTime = 0;␊ |
659 | ␉␉break;␊ |
660 | ␉default:␊ |
661 | ␉␉break;␊ |
662 | ␉}␊ |
663 | ␊ |
664 | ␉if (time != 0)␊ |
665 | ␉{␊ |
666 | ␉␉// Convert base time from 1904 to 1970.␊ |
667 | ␉␉*time = tmpTime - 2082844800;␊ |
668 | ␉}␊ |
669 | ␊ |
670 | ␉if (infoValid)␊ |
671 | ␉{␊ |
672 | ␉␉*infoValid = valid;␊ |
673 | ␉}␊ |
674 | ␊ |
675 | ␉return 0L;␊ |
676 | }␊ |
677 | ␊ |
678 | //==============================================================================␊ |
679 | ␊ |
680 | static long ResolvePathToCatalogEntry(char * filePath, long * flags, void * entry, u_int32_t dirID, long long * dirIndex)␊ |
681 | {␊ |
682 | ␉char␉␉␉*restPath;␊ |
683 | ␉long␉␉␉result, cnt;␊ |
684 | ␉u_int32_t␉␉subFolderID = 0;␊ |
685 | ␉long long␉␉tmpDirIndex;␊ |
686 | ␉HFSPlusCatalogFile␉*hfsPlusFile;␊ |
687 | ␊ |
688 | ␉// Copy the file name to gTempStr␊ |
689 | ␉cnt = 0;␊ |
690 | ␊ |
691 | ␉while ((filePath[cnt] != '/') && (filePath[cnt] != '\0'))␊ |
692 | ␉{␊ |
693 | ␉␉cnt++;␊ |
694 | ␉}␊ |
695 | ␊ |
696 | ␉strlcpy(gTempStr, filePath, cnt+1);␊ |
697 | ␊ |
698 | ␉// Move restPath to the right place.␊ |
699 | ␉if (filePath[cnt] != '\0')␊ |
700 | ␉{␊ |
701 | ␉␉cnt++;␊ |
702 | ␉}␊ |
703 | ␊ |
704 | ␉restPath = filePath + cnt;␊ |
705 | ␊ |
706 | ␉// gTempStr is a name in the current Dir.␊ |
707 | ␉// restPath is the rest of the path if any.␊ |
708 | ␊ |
709 | ␉result = ReadCatalogEntry(gTempStr, dirID, entry, dirIndex);␊ |
710 | ␊ |
711 | ␉if (result == -1)␊ |
712 | ␉{␊ |
713 | ␉␉return -1;␊ |
714 | ␉}␊ |
715 | ␊ |
716 | ␉GetCatalogEntryInfo(entry, flags, 0, 0, 0);␊ |
717 | ␊ |
718 | ␉if ((*flags & kFileTypeMask) == kFileTypeDirectory)␊ |
719 | ␉{␊ |
720 | ␉␉if (gIsHFSPlus)␊ |
721 | ␉␉{␊ |
722 | ␉␉␉subFolderID = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->folderID);␊ |
723 | ␉␉}␊ |
724 | ␉␉else␊ |
725 | ␉␉{␊ |
726 | ␉␉␉subFolderID = SWAP_BE32(((HFSCatalogFolder *)entry)->folderID);␊ |
727 | ␉␉}␊ |
728 | ␉}␊ |
729 | ␊ |
730 | ␉if ((*flags & kFileTypeMask) == kFileTypeDirectory)␊ |
731 | ␉{␊ |
732 | ␉␉result = ResolvePathToCatalogEntry(restPath, flags, entry, subFolderID, dirIndex);␊ |
733 | ␉}␊ |
734 | ␊ |
735 | ␉if (gIsHFSPlus && ((*flags & kFileTypeMask) == kFileTypeFlat))␊ |
736 | ␉{␊ |
737 | ␉␉hfsPlusFile = (HFSPlusCatalogFile *)entry;␊ |
738 | ␊ |
739 | ␉␉if ((SWAP_BE32(hfsPlusFile->userInfo.fdType) == kHardLinkFileType) && (SWAP_BE32(hfsPlusFile->userInfo.fdCreator) == kHFSPlusCreator))␊ |
740 | ␉␉{␊ |
741 | ␉␉␉sprintf(gLinkTemp, "%s/%s%d", HFSPLUSMETADATAFOLDER, HFS_INODE_PREFIX, SWAP_BE32(hfsPlusFile->bsdInfo.special.iNodeNum));␊ |
742 | ␉␉␉result = ResolvePathToCatalogEntry(gLinkTemp, flags, entry, kHFSRootFolderID, &tmpDirIndex);␊ |
743 | ␉␉}␊ |
744 | ␉}␊ |
745 | ␊ |
746 | ␉return result;␊ |
747 | }␊ |
748 | ␊ |
749 | //==============================================================================␊ |
750 | ␊ |
751 | static long GetCatalogEntry(long long * dirIndex, char ** name, long * flags, u_int32_t * time, FinderInfo * finderInfo, long * infoValid)␊ |
752 | {␊ |
753 | ␉u_int64_t extentSize;␊ |
754 | ␉void *extent;␊ |
755 | ␉char *nodeBuf, *testKey, *entry;␊ |
756 | ␉BTNodeDescriptor *node;␊ |
757 | ␉u_int32_t curNode;␊ |
758 | ␉u_int16_t nodeSize, index;␊ |
759 | ␊ |
760 | ␉if (gIsHFSPlus)␊ |
761 | ␉{␊ |
762 | ␉␉extent = &gHFSPlus->catalogFile.extents;␊ |
763 | ␉␉extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);␊ |
764 | ␉}␊ |
765 | ␉else␊ |
766 | ␉{␊ |
767 | ␉␉extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;␊ |
768 | ␉␉extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);␊ |
769 | ␉}␊ |
770 | ␊ |
771 | ␉nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);␊ |
772 | ␉nodeBuf = (char *)malloc(nodeSize);␊ |
773 | ␉node = (BTNodeDescriptor *)nodeBuf;␊ |
774 | ␊ |
775 | ␉index = (u_int16_t) (*dirIndex % nodeSize);␊ |
776 | ␉curNode = (u_int32_t) (*dirIndex / nodeSize);␊ |
777 | ␊ |
778 | ␉// Read the BTree node and get the record for index.␊ |
779 | ␉ReadExtent(extent, extentSize, kHFSCatalogFileID, (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);␊ |
780 | ␊ |
781 | ␉GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);␊ |
782 | ␊ |
783 | ␉GetCatalogEntryInfo(entry, flags, time, finderInfo, infoValid);␊ |
784 | ␊ |
785 | ␉// Get the file name.␊ |
786 | ␉if (gIsHFSPlus)␊ |
787 | ␉{␊ |
788 | ␉␉utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,␊ |
789 | SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),␊ |
790 | (u_int8_t *)gTempStr, 256, OSBigEndian);␊ |
791 | ␉}␊ |
792 | ␉else␊ |
793 | ␉{␊ |
794 | ␉␉strncpy(gTempStr, (const char *)&((HFSCatalogKey *)testKey)->nodeName[1], ((HFSCatalogKey *)testKey)->nodeName[0]);␊ |
795 | ␊ |
796 | ␉␉gTempStr[((HFSCatalogKey *)testKey)->nodeName[0]] = '\0';␊ |
797 | ␉}␊ |
798 | ␊ |
799 | ␉*name = gTempStr;␊ |
800 | ␊ |
801 | ␉// Update dirIndex.␊ |
802 | ␉index++;␊ |
803 | ␊ |
804 | ␉if (index == SWAP_BE16(node->numRecords))␊ |
805 | ␉{␊ |
806 | ␉␉index = 0;␊ |
807 | ␉␉curNode = SWAP_BE32(node->fLink);␊ |
808 | ␉}␊ |
809 | ␊ |
810 | ␉*dirIndex = (long long) curNode * nodeSize + index;␊ |
811 | ␊ |
812 | ␉free(nodeBuf);␊ |
813 | ␊ |
814 | ␉return 0;␊ |
815 | }␊ |
816 | ␊ |
817 | //==============================================================================␊ |
818 | ␊ |
819 | static long ReadCatalogEntry(char * fileName, u_int32_t dirID, void * entry, long long * dirIndex)␊ |
820 | {␊ |
821 | ␉long length = strlen(fileName);␊ |
822 | ␉char key[sizeof(HFSPlusCatalogKey)];␊ |
823 | ␉HFSCatalogKey *hfsKey = (HFSCatalogKey *)key;␊ |
824 | ␉HFSPlusCatalogKey *hfsPlusKey = (HFSPlusCatalogKey *)key;␊ |
825 | ␊ |
826 | ␉// Make the catalog key.␊ |
827 | ␉if ( gIsHFSPlus )␊ |
828 | ␉{␊ |
829 | ␉␉if (length > kHFSPlusMaxFileNameChars)␊ |
830 | ␉␉{␊ |
831 | ␉␉␉length = kHFSPlusMaxFileNameChars;␊ |
832 | ␉␉}␊ |
833 | ␊ |
834 | ␉␉hfsPlusKey->parentID = SWAP_BE32(dirID);␊ |
835 | ␊ |
836 | ␉␉utf_decodestr((u_int8_t *)fileName, hfsPlusKey->nodeName.unicode, &(hfsPlusKey->nodeName.length), 512, OSBigEndian);␊ |
837 | ␉}␊ |
838 | ␉else␊ |
839 | ␉{␊ |
840 | ␉␉if (length > kHFSMaxFileNameChars)␊ |
841 | ␉␉{␊ |
842 | ␉␉␉length = kHFSMaxFileNameChars;␊ |
843 | ␉␉}␊ |
844 | ␊ |
845 | ␉␉hfsKey->parentID = SWAP_BE32(dirID);␊ |
846 | ␊ |
847 | ␉␉hfsKey->nodeName[0] = length;␊ |
848 | ␉␉strncpy((char *)(hfsKey->nodeName + 1), fileName, length);␊ |
849 | ␉}␊ |
850 | ␊ |
851 | ␉return ReadBTreeEntry(kBTreeCatalog, &key, entry, dirIndex);␊ |
852 | }␊ |
853 | ␊ |
854 | //==============================================================================␊ |
855 | ␊ |
856 | static long ReadExtentsEntry(u_int32_t fileID, long startBlock, void * entry)␊ |
857 | {␊ |
858 | ␉char key[sizeof(HFSPlusExtentKey)];␊ |
859 | ␉HFSExtentKey *hfsKey = (HFSExtentKey *)key;␊ |
860 | ␉HFSPlusExtentKey *hfsPlusKey = (HFSPlusExtentKey *)key;␊ |
861 | ␊ |
862 | ␉// Make the extents key.␊ |
863 | ␉if (gIsHFSPlus)␊ |
864 | ␉{␊ |
865 | ␉␉hfsPlusKey->forkType = 0;␊ |
866 | ␉␉hfsPlusKey->fileID = SWAP_BE32(fileID);␊ |
867 | ␉␉hfsPlusKey->startBlock = SWAP_BE32(startBlock);␊ |
868 | ␉}␊ |
869 | ␉else␊ |
870 | ␉{␊ |
871 | ␉␉hfsKey->forkType = 0;␊ |
872 | ␉␉hfsKey->fileID = SWAP_BE32(fileID);␊ |
873 | ␉␉hfsKey->startBlock = SWAP_BE16(startBlock);␊ |
874 | ␉}␊ |
875 | ␊ |
876 | ␉return ReadBTreeEntry(kBTreeExtents, &key, entry, 0);␊ |
877 | }␊ |
878 | ␊ |
879 | //==============================================================================␊ |
880 | ␊ |
881 | static long ReadBTreeEntry(long btree, void * key, char * entry, long long * dirIndex)␊ |
882 | {␊ |
883 | ␉u_int64_t extentSize;␊ |
884 | ␉void *extent;␊ |
885 | ␉u_int16_t extentFile;␊ |
886 | ␉char *nodeBuf;␊ |
887 | ␉BTNodeDescriptor *node;␊ |
888 | ␉long result = 0, entrySize = 0;␊ |
889 | ␉u_int32_t curNode;␊ |
890 | ␉char *testKey, *recordData;␊ |
891 | ␉u_int16_t nodeSize, index = 0, lowerBound, upperBound;␊ |
892 | ␊ |
893 | ␉// Figure out which tree is being looked at.␊ |
894 | ␉if (btree == kBTreeCatalog)␊ |
895 | ␉{␊ |
896 | ␉␉if (gIsHFSPlus) ␊ |
897 | ␉␉{␊ |
898 | ␉␉␉extent = &gHFSPlus->catalogFile.extents;␊ |
899 | ␉␉␉extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);␊ |
900 | ␉␉}␊ |
901 | ␉␉else␊ |
902 | ␉␉{␊ |
903 | ␉␉␉extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;␊ |
904 | ␉␉␉extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);␊ |
905 | ␉␉}␊ |
906 | ␉␉extentFile = kHFSCatalogFileID;␊ |
907 | ␉}␊ |
908 | ␉else␊ |
909 | ␉{␊ |
910 | ␉␉if (gIsHFSPlus)␊ |
911 | ␉␉{␊ |
912 | ␉␉␉extent = &gHFSPlus->extentsFile.extents;␊ |
913 | ␉␉␉extentSize = SWAP_BE64(gHFSPlus->extentsFile.logicalSize);␊ |
914 | ␉␉}␊ |
915 | ␉␉else␊ |
916 | ␉␉{␊ |
917 | ␉␉␉extent = (HFSExtentDescriptor *)&gHFSMDB->drXTExtRec;␊ |
918 | ␉␉␉extentSize = SWAP_BE32(gHFSMDB->drXTFlSize);␊ |
919 | ␉␉}␊ |
920 | ␉␉extentFile = kHFSExtentsFileID;␊ |
921 | ␉}␊ |
922 | ␊ |
923 | ␉// Read the BTree Header if needed.␊ |
924 | ␉if (gBTHeaders[btree] == 0)␊ |
925 | ␉{␊ |
926 | ␉␉ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + btree * 256, 0);␊ |
927 | ␉␉gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 + sizeof(BTNodeDescriptor));␊ |
928 | ␊ |
929 | ␉␉if ((gIsHFSPlus && btree == kBTreeCatalog) && (gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare))␊ |
930 | ␉␉{␊ |
931 | ␉␉␉gCaseSensitive = 1;␊ |
932 | ␉␉}␊ |
933 | ␉}␊ |
934 | ␊ |
935 | ␉curNode = SWAP_BE32(gBTHeaders[btree]->rootNode);␊ |
936 | ␉nodeSize = SWAP_BE16(gBTHeaders[btree]->nodeSize);␊ |
937 | ␉nodeBuf = (char *)malloc(nodeSize);␊ |
938 | ␊ |
939 | ␉if (!nodeBuf) ␊ |
940 | ␉{␊ |
941 | ␉␉return -1;␊ |
942 | ␉}␊ |
943 | ␊ |
944 | ␉node = (BTNodeDescriptor *)nodeBuf;␊ |
945 | ␊ |
946 | ␉while (1)␊ |
947 | ␉{␊ |
948 | ␉␉// Read the current node.␊ |
949 | ␉ReadExtent(extent, extentSize, extentFile, (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);␊ |
950 | ␊ |
951 | ␉␉// Find the matching key.␊ |
952 | ␉␉lowerBound = 0;␊ |
953 | ␉␉upperBound = SWAP_BE16(node->numRecords) - 1;␊ |
954 | ␊ |
955 | ␉␉while (lowerBound <= upperBound)␊ |
956 | ␉␉{␊ |
957 | ␉␉␉index = (lowerBound + upperBound) / 2;␊ |
958 | ␊ |
959 | ␉␉␉GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);␊ |
960 | ␊ |
961 | ␉␉␉if (gIsHFSPlus)␊ |
962 | ␉␉␉{␊ |
963 | ␉␉␉␉if (btree == kBTreeCatalog)␊ |
964 | ␉␉␉␉{␊ |
965 | ␉␉␉␉␉result = CompareHFSPlusCatalogKeys(key, testKey);␊ |
966 | ␉␉␉␉}␊ |
967 | ␉␉␉␉else␊ |
968 | ␉␉␉␉{␊ |
969 | ␉␉␉␉␉result = CompareHFSPlusExtentsKeys(key, testKey);␊ |
970 | ␉␉␉␉}␊ |
971 | ␉␉␉}␊ |
972 | ␉␉␉else␊ |
973 | ␉␉␉{␊ |
974 | ␉␉␉␉if (btree == kBTreeCatalog)␊ |
975 | ␉␉␉␉{␊ |
976 | ␉␉␉␉␉result = CompareHFSCatalogKeys(key, testKey);␊ |
977 | ␉␉␉␉}␊ |
978 | ␉␉␉␉else␊ |
979 | ␉␉␉␉{␊ |
980 | ␉␉␉␉␉result = CompareHFSExtentsKeys(key, testKey);␊ |
981 | ␉␉␉␉}␊ |
982 | ␉␉␉}␊ |
983 | ␊ |
984 | ␉␉␉if (result < 0)␊ |
985 | ␉␉␉{␊ |
986 | ␉␉␉␉upperBound = index - 1;␉// search < trial␊ |
987 | ␉␉␉}␊ |
988 | ␉␉␉else if (result > 0)␊ |
989 | ␉␉␉{␊ |
990 | ␉␉␉␉lowerBound = index + 1;␉// search > trial␊ |
991 | ␉␉␉}␊ |
992 | ␉␉␉else␊ |
993 | ␉␉␉{␊ |
994 | ␉␉␉␉break;␉␉␉// search = trial␊ |
995 | ␉␉␉}␊ |
996 | ␉␉}␊ |
997 | ␊ |
998 | ␉␉if (result < 0)␊ |
999 | ␉␉{␊ |
1000 | ␉␉␉index = upperBound;␊ |
1001 | ␉␉␉GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);␊ |
1002 | ␉␉}␊ |
1003 | ␊ |
1004 | ␉␉// Found the closest key... Recurse on it if this is an index node.␊ |
1005 | ␉␉if (node->kind == kBTIndexNode)␊ |
1006 | ␉␉{␊ |
1007 | ␉␉␉curNode = SWAP_BE32( *((long *)recordData) );␊ |
1008 | ␉␉}␊ |
1009 | ␉␉else␊ |
1010 | ␉␉{␊ |
1011 | ␉␉␉break;␊ |
1012 | ␉␉}␊ |
1013 | ␉}␊ |
1014 | ␊ |
1015 | ␉// Return error if the file was not found.␊ |
1016 | ␉if (result != 0 || !recordData)␊ |
1017 | ␉{␊ |
1018 | ␉␉free(nodeBuf);␊ |
1019 | ␉␉return -1;␊ |
1020 | ␉}␊ |
1021 | ␊ |
1022 | ␉if (btree == kBTreeCatalog)␊ |
1023 | ␉{␊ |
1024 | ␉␉switch (SWAP_BE16(*(short *)recordData))␊ |
1025 | ␉␉{␊ |
1026 | ␉␉␉case kHFSFolderRecord : entrySize = 70;␊ |
1027 | ␉␉␉␉break;␊ |
1028 | ␉␉␉case kHFSFileRecord : entrySize = 102;␊ |
1029 | ␉␉␉␉break;␊ |
1030 | ␉␉␉case kHFSFolderThreadRecord : entrySize = 46;␊ |
1031 | ␉␉␉␉break;␊ |
1032 | ␉␉␉case kHFSFileThreadRecord : entrySize = 46;␊ |
1033 | ␉␉␉␉break;␊ |
1034 | ␉␉␉case kHFSPlusFolderRecord : entrySize = 88;␊ |
1035 | ␉␉␉␉break;␊ |
1036 | ␉␉␉case kHFSPlusFileRecord : entrySize = 248;␊ |
1037 | ␉␉␉␉break;␊ |
1038 | ␉␉␉case kHFSPlusFolderThreadRecord : entrySize = 264;␊ |
1039 | ␉␉␉␉break;␊ |
1040 | ␉␉␉case kHFSPlusFileThreadRecord : entrySize = 264;␊ |
1041 | ␉␉␉␉break;␊ |
1042 | ␉␉␉default:␊ |
1043 | ␉␉␉␉break;␊ |
1044 | ␉␉}␊ |
1045 | ␉}␊ |
1046 | ␉else␊ |
1047 | ␉{␊ |
1048 | ␉␉if (gIsHFSPlus)␊ |
1049 | ␉␉{␊ |
1050 | ␉␉␉entrySize = sizeof(HFSPlusExtentRecord);␊ |
1051 | ␉␉}␊ |
1052 | ␉␉else␊ |
1053 | ␉␉{␊ |
1054 | ␉␉␉entrySize = sizeof(HFSExtentRecord);␊ |
1055 | ␉␉}␊ |
1056 | ␉}␊ |
1057 | ␊ |
1058 | ␉bcopy(recordData, entry, entrySize);␊ |
1059 | ␊ |
1060 | ␉// Update dirIndex.␊ |
1061 | ␉if (dirIndex != 0)␊ |
1062 | ␉{␊ |
1063 | ␉␉index++;␊ |
1064 | ␊ |
1065 | ␉␉if (index == SWAP_BE16(node->numRecords))␊ |
1066 | ␉␉{␊ |
1067 | ␉␉␉index = 0;␊ |
1068 | ␉␉␉curNode = SWAP_BE32(node->fLink);␊ |
1069 | ␉␉}␊ |
1070 | ␊ |
1071 | ␉␉*dirIndex = (long long) curNode * nodeSize + index;␊ |
1072 | ␉}␊ |
1073 | ␊ |
1074 | ␉free(nodeBuf);␊ |
1075 | ␊ |
1076 | ␉return 0;␊ |
1077 | }␊ |
1078 | ␊ |
1079 | //==============================================================================␊ |
1080 | ␊ |
1081 | static void GetBTreeRecord(u_int16_t index, char * nodeBuffer, u_int16_t nodeSize, char ** key, char ** data)␊ |
1082 | {␊ |
1083 | ␉u_int16_t recordOffset, keySize;␊ |
1084 | ␊ |
1085 | ␉recordOffset = SWAP_BE16(*((u_int16_t *)(nodeBuffer + (nodeSize - 2 * index - 2))));␊ |
1086 | ␉*key = nodeBuffer + recordOffset;␊ |
1087 | ␊ |
1088 | ␉if (gIsHFSPlus)␊ |
1089 | ␉{␊ |
1090 | ␉␉keySize = SWAP_BE16(*(u_int16_t *)*key);␊ |
1091 | ␉␉*data = *key + 2 + keySize;␊ |
1092 | ␉}␊ |
1093 | ␉else␊ |
1094 | ␉{␊ |
1095 | ␉␉keySize = **key;␊ |
1096 | ␉␉*data = *key + 2 + keySize - (keySize & 1);␊ |
1097 | ␉}␊ |
1098 | }␊ |
1099 | ␊ |
1100 | //==============================================================================␊ |
1101 | ␊ |
1102 | static long ReadExtent(char * extent, u_int64_t extentSize, u_int32_t extentFile, u_int64_t offset, u_int64_t size, void * buffer, long cache)␊ |
1103 | {␊ |
1104 | ␉u_int64_t lastOffset;␊ |
1105 | ␉u_int64_t blockNumber, countedBlocks = 0;␊ |
1106 | ␉u_int64_t nextExtent = 0, sizeRead = 0, readSize;␊ |
1107 | ␉u_int64_t nextExtentBlock, currentExtentBlock = 0;␊ |
1108 | ␉u_int64_t readOffset;␊ |
1109 | ␉u_int64_t extentDensity, sizeofExtent, currentExtentSize;␊ |
1110 | ␉char *currentExtent, *extentBuffer = 0, *bufferPos = buffer;␊ |
1111 | ␊ |
1112 | ␉if (offset >= extentSize)␊ |
1113 | ␉{␊ |
1114 | ␉␉return 0;␊ |
1115 | ␉}␊ |
1116 | ␊ |
1117 | ␉if (gIsHFSPlus)␊ |
1118 | ␉{␊ |
1119 | ␉␉extentDensity = kHFSPlusExtentDensity;␊ |
1120 | ␉␉sizeofExtent = sizeof(HFSPlusExtentDescriptor);␊ |
1121 | ␉}␊ |
1122 | ␉else␊ |
1123 | ␉{␊ |
1124 | ␉␉extentDensity = kHFSExtentDensity;␊ |
1125 | ␉␉sizeofExtent = sizeof(HFSExtentDescriptor);␊ |
1126 | ␉}␊ |
1127 | ␊ |
1128 | ␉lastOffset = offset + size;␊ |
1129 | ␊ |
1130 | ␉while (offset < lastOffset)␊ |
1131 | ␉{␊ |
1132 | ␉␉blockNumber = offset / gBlockSize;␊ |
1133 | ␊ |
1134 | ␉␉// Find the extent for the offset.␊ |
1135 | ␉␉for (; ; nextExtent++)␊ |
1136 | ␉␉{␊ |
1137 | ␉␉␉if (nextExtent < extentDensity)␊ |
1138 | ␉␉␉{␊ |
1139 | ␉␉␉␉if ((countedBlocks + GetExtentSize(extent, nextExtent) -1) < blockNumber)␊ |
1140 | ␉␉␉␉{␊ |
1141 | ␉␉␉␉␉countedBlocks += GetExtentSize(extent, nextExtent);␊ |
1142 | ␉␉␉␉␉continue;␊ |
1143 | ␉␉␉␉}␊ |
1144 | ␊ |
1145 | ␉␉␉␉currentExtent = extent + nextExtent * sizeofExtent;␊ |
1146 | ␉␉␉␉break;␊ |
1147 | ␉␉␉}␊ |
1148 | ␊ |
1149 | ␉␉␉if (extentBuffer == 0)␊ |
1150 | ␉␉␉{␊ |
1151 | ␉␉␉␉extentBuffer = malloc(sizeofExtent * extentDensity);␊ |
1152 | ␊ |
1153 | ␉␉␉␉if (extentBuffer == 0)␊ |
1154 | ␉␉␉␉{␊ |
1155 | ␉␉␉␉␉return -1;␊ |
1156 | ␉␉␉␉}␊ |
1157 | ␉␉␉}␊ |
1158 | ␊ |
1159 | ␉␉␉nextExtentBlock = nextExtent / extentDensity;␊ |
1160 | ␊ |
1161 | ␉␉␉if (currentExtentBlock != nextExtentBlock)␊ |
1162 | ␉␉␉{␊ |
1163 | ␉␉␉␉ReadExtentsEntry(extentFile, countedBlocks, extentBuffer);␊ |
1164 | ␉␉␉␉currentExtentBlock = nextExtentBlock;␊ |
1165 | ␉␉␉}␊ |
1166 | ␊ |
1167 | ␉␉␉currentExtentSize = GetExtentSize(extentBuffer, nextExtent % extentDensity);␊ |
1168 | ␊ |
1169 | ␉␉␉if ((countedBlocks + currentExtentSize - 1) >= blockNumber)␊ |
1170 | ␉␉␉{␊ |
1171 | ␉␉␉␉currentExtent = extentBuffer + sizeofExtent * (nextExtent % extentDensity);␊ |
1172 | ␉␉␉␉break;␊ |
1173 | ␉␉␉}␊ |
1174 | ␊ |
1175 | ␉␉␉countedBlocks += currentExtentSize;␊ |
1176 | ␉␉}␊ |
1177 | ␊ |
1178 | ␉␉readOffset = ((blockNumber - countedBlocks) * gBlockSize) + (offset % gBlockSize);␊ |
1179 | ␊ |
1180 | ␉␉readSize = (long long)GetExtentSize(currentExtent, 0) * gBlockSize - readOffset;␊ |
1181 | ␊ |
1182 | ␉␉if (readSize > (size - sizeRead))␊ |
1183 | ␉␉{␊ |
1184 | ␉␉␉readSize = size - sizeRead;␊ |
1185 | ␉␉}␊ |
1186 | ␊ |
1187 | ␉␉readOffset += (long long)GetExtentStart(currentExtent, 0) * gBlockSize;␊ |
1188 | ␊ |
1189 | ␉␉CacheRead(gCurrentIH, bufferPos, gAllocationOffset + readOffset, readSize, cache);␊ |
1190 | ␊ |
1191 | ␉␉sizeRead += readSize;␊ |
1192 | ␉␉offset += readSize;␊ |
1193 | ␉␉bufferPos += readSize;␊ |
1194 | ␉}␊ |
1195 | ␊ |
1196 | ␉if (extentBuffer)␊ |
1197 | ␉{␊ |
1198 | ␉␉free(extentBuffer);␊ |
1199 | ␉}␊ |
1200 | ␊ |
1201 | ␉return sizeRead;␊ |
1202 | }␊ |
1203 | ␊ |
1204 | //==============================================================================␊ |
1205 | ␊ |
1206 | static u_int32_t GetExtentStart(void * extents, u_int32_t index)␊ |
1207 | {␊ |
1208 | ␉u_int32_t start;␊ |
1209 | ␊ |
1210 | ␉HFSExtentDescriptor␉␉*hfsExtents␉␉= extents;␊ |
1211 | ␉HFSPlusExtentDescriptor␉*hfsPlusExtents␉= extents;␊ |
1212 | ␊ |
1213 | ␉if (gIsHFSPlus)␊ |
1214 | ␉{␊ |
1215 | ␉␉start = SWAP_BE32(hfsPlusExtents[index].startBlock);␊ |
1216 | ␉}␊ |
1217 | ␉else␊ |
1218 | ␉{␊ |
1219 | ␉␉start = SWAP_BE16(hfsExtents[index].startBlock);␊ |
1220 | ␉}␊ |
1221 | ␊ |
1222 | ␉return start;␊ |
1223 | }␊ |
1224 | ␊ |
1225 | //==============================================================================␊ |
1226 | ␊ |
1227 | static u_int32_t GetExtentSize(void * extents, u_int32_t index)␊ |
1228 | {␊ |
1229 | ␉u_int32_t size = 0L;␊ |
1230 | ␊ |
1231 | ␉HFSExtentDescriptor *hfsExtents = extents;␊ |
1232 | ␉HFSPlusExtentDescriptor *hfsPlusExtents = extents;␊ |
1233 | ␊ |
1234 | ␉if (gIsHFSPlus)␊ |
1235 | ␉{␊ |
1236 | ␉␉size = SWAP_BE32(hfsPlusExtents[index].blockCount);␊ |
1237 | ␉}␊ |
1238 | ␉else␊ |
1239 | ␉{␊ |
1240 | ␉␉size = SWAP_BE16(hfsExtents[index].blockCount);␊ |
1241 | ␉}␊ |
1242 | ␊ |
1243 | ␉return size;␊ |
1244 | }␊ |
1245 | ␊ |
1246 | //==============================================================================␊ |
1247 | ␊ |
1248 | static long CompareHFSCatalogKeys(void * key, void * testKey)␊ |
1249 | {␊ |
1250 | ␉HFSCatalogKey *searchKey, *trialKey;␊ |
1251 | ␉long result, searchParentID, trialParentID;␊ |
1252 | ␊ |
1253 | ␉searchKey = key;␊ |
1254 | ␉trialKey = testKey;␊ |
1255 | ␊ |
1256 | ␉searchParentID = SWAP_BE32(searchKey->parentID);␊ |
1257 | ␉trialParentID = SWAP_BE32(trialKey->parentID);␊ |
1258 | ␊ |
1259 | ␉// parent dirID is unsigned␊ |
1260 | ␉if (searchParentID > trialParentID)␊ |
1261 | ␉{␊ |
1262 | ␉␉result = 1;␊ |
1263 | ␉}␊ |
1264 | ␉else if (searchParentID < trialParentID)␊ |
1265 | ␉{␊ |
1266 | ␉␉result = -1;␊ |
1267 | ␉}␊ |
1268 | ␉else␊ |
1269 | ␉{␊ |
1270 | ␉␉// parent dirID's are equal, compare names␊ |
1271 | ␉␉result = FastRelString(searchKey->nodeName, trialKey->nodeName);␊ |
1272 | ␉}␊ |
1273 | ␊ |
1274 | ␉return result;␊ |
1275 | }␊ |
1276 | ␊ |
1277 | //==============================================================================␊ |
1278 | ␊ |
1279 | static long CompareHFSPlusCatalogKeys(void * key, void * testKey)␊ |
1280 | {␊ |
1281 | ␉HFSPlusCatalogKey *searchKey, *trialKey;␊ |
1282 | ␉long result, searchParentID, trialParentID;␊ |
1283 | ␊ |
1284 | ␉searchKey = key;␊ |
1285 | ␉trialKey = testKey;␊ |
1286 | ␊ |
1287 | ␉searchParentID = SWAP_BE32(searchKey->parentID);␊ |
1288 | ␉trialParentID = SWAP_BE32(trialKey->parentID);␊ |
1289 | ␊ |
1290 | ␉// parent dirID is unsigned␊ |
1291 | ␉if (searchParentID > trialParentID)␊ |
1292 | ␉{␊ |
1293 | ␉␉result = 1;␊ |
1294 | ␉}␊ |
1295 | ␉else if (searchParentID < trialParentID)␊ |
1296 | ␉{␊ |
1297 | ␉␉result = -1;␊ |
1298 | ␉}␊ |
1299 | ␉else␊ |
1300 | ␉{␊ |
1301 | ␉␉// parent dirID's are equal, compare names␊ |
1302 | ␉␉if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0))␊ |
1303 | ␉␉{␊ |
1304 | ␉␉␉result = searchKey->nodeName.length - trialKey->nodeName.length;␊ |
1305 | ␉␉}␊ |
1306 | ␉␉else if (gCaseSensitive)␊ |
1307 | ␉␉{␊ |
1308 | ␉␉␉result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0],␊ |
1309 | SWAP_BE16(searchKey->nodeName.length),␊ |
1310 | &trialKey->nodeName.unicode[0],␊ |
1311 | SWAP_BE16(trialKey->nodeName.length));␊ |
1312 | ␉␉}␊ |
1313 | ␉␉else␊ |
1314 | ␉␉{␊ |
1315 | ␉␉␉result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],␊ |
1316 | SWAP_BE16(searchKey->nodeName.length),␊ |
1317 | &trialKey->nodeName.unicode[0],␊ |
1318 | SWAP_BE16(trialKey->nodeName.length), OSBigEndian);␊ |
1319 | ␉␉}␊ |
1320 | ␉}␊ |
1321 | ␊ |
1322 | ␉return result;␊ |
1323 | }␊ |
1324 | ␊ |
1325 | //==============================================================================␊ |
1326 | ␊ |
1327 | static long CompareHFSExtentsKeys(void * key, void * testKey)␊ |
1328 | {␊ |
1329 | ␉HFSExtentKey *searchKey, *trialKey;␊ |
1330 | ␉long result;␊ |
1331 | ␊ |
1332 | ␉searchKey = key;␊ |
1333 | ␉trialKey = testKey;␊ |
1334 | ␊ |
1335 | ␉// assume searchKey < trialKey␊ |
1336 | ␉result = -1; ␊ |
1337 | ␊ |
1338 | ␉if (searchKey->fileID == trialKey->fileID)␊ |
1339 | ␉{␊ |
1340 | ␉␉// FileNum's are equal; compare fork types␊ |
1341 | ␉␉if (searchKey->forkType == trialKey->forkType)␊ |
1342 | ␉␉{␊ |
1343 | ␉␉␉// Fork types are equal; compare allocation block number␊ |
1344 | ␉␉␉if (searchKey->startBlock == trialKey->startBlock)␊ |
1345 | ␉␉␉{␊ |
1346 | ␉␉␉␉// Everything is equal␊ |
1347 | ␉␉␉␉result = 0;␊ |
1348 | ␉␉␉}␊ |
1349 | ␉␉␉else␊ |
1350 | ␉␉␉{␊ |
1351 | ␉␉␉␉// Allocation block numbers differ; determine sign␊ |
1352 | ␉␉␉␉if (SWAP_BE16(searchKey->startBlock) > SWAP_BE16(trialKey->startBlock))␊ |
1353 | ␉␉␉␉{␊ |
1354 | ␉␉␉␉␉result = 1;␊ |
1355 | ␉␉␉␉}␊ |
1356 | ␉␉␉}␊ |
1357 | ␉}␊ |
1358 | ␉␉else␊ |
1359 | ␉␉{␊ |
1360 | ␉␉␉// Fork types differ; determine sign␊ |
1361 | ␉␉␉if (searchKey->forkType > trialKey->forkType)␊ |
1362 | ␉␉␉{␊ |
1363 | ␉␉␉␉result = 1;␊ |
1364 | ␉␉␉}␊ |
1365 | ␉␉}␊ |
1366 | ␉}␊ |
1367 | ␉else␊ |
1368 | ␉{␊ |
1369 | ␉␉// FileNums differ; determine sign␊ |
1370 | ␉␉if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))␊ |
1371 | ␉␉{␊ |
1372 | ␉␉␉result = 1;␊ |
1373 | ␉␉}␊ |
1374 | ␉}␊ |
1375 | ␊ |
1376 | ␉return result;␊ |
1377 | }␊ |
1378 | ␊ |
1379 | ␊ |
1380 | //==============================================================================␊ |
1381 | ␊ |
1382 | static long CompareHFSPlusExtentsKeys(void * key, void * testKey)␊ |
1383 | {␊ |
1384 | ␉HFSPlusExtentKey␉*searchKey, *trialKey;␊ |
1385 | ␊ |
1386 | ␉long␉␉␉result = -1; // assume searchKey < trialKey␊ |
1387 | ␊ |
1388 | ␉searchKey = key;␊ |
1389 | ␉trialKey = testKey;␊ |
1390 | ␊ |
1391 | ␉if (searchKey->fileID == trialKey->fileID)␊ |
1392 | ␉{␊ |
1393 | ␉␉// FileNum's are equal; compare fork types␊ |
1394 | ␉␉if (searchKey->forkType == trialKey->forkType)␊ |
1395 | ␉␉{␊ |
1396 | ␉␉␉// Fork types are equal; compare allocation block number␊ |
1397 | ␉␉␉if (searchKey->startBlock == trialKey->startBlock)␊ |
1398 | ␉␉␉{␊ |
1399 | ␉␉␉␉// Everything is equal␊ |
1400 | ␉␉␉␉result = 0;␊ |
1401 | ␉␉␉}␊ |
1402 | ␉␉␉else␊ |
1403 | ␉␉␉{␊ |
1404 | ␉␉␉␉// Allocation block numbers differ; determine sign␊ |
1405 | ␉␉␉␉if (SWAP_BE32(searchKey->startBlock) > SWAP_BE32(trialKey->startBlock))␊ |
1406 | ␉␉␉␉{␊ |
1407 | ␉␉␉␉␉result = 1;␊ |
1408 | ␉␉␉␉}␊ |
1409 | ␉␉␉}␊ |
1410 | ␉␉}␊ |
1411 | ␉␉else␊ |
1412 | ␉␉{␊ |
1413 | ␉␉␉// Fork types differ; determine sign␊ |
1414 | ␉␉␉if (searchKey->forkType > trialKey->forkType)␊ |
1415 | ␉␉␉{␊ |
1416 | ␉␉␉␉result = 1;␊ |
1417 | ␉␉␉}␊ |
1418 | ␉␉}␊ |
1419 | ␉}␊ |
1420 | ␉else␊ |
1421 | ␉{␊ |
1422 | ␉␉// FileNums differ; determine sign␊ |
1423 | ␉␉if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))␊ |
1424 | ␉␉{␊ |
1425 | ␉␉␉result = 1;␊ |
1426 | ␉␉}␊ |
1427 | ␉}␊ |
1428 | ␊ |
1429 | ␉return result;␊ |
1430 | }␊ |
1431 | ␊ |
1432 |