Root/
Source at commit 284 created 13 years 10 months ago. By blackosx, Amended my mistake by updating the Default theme images in the trunk. Now put them back as they were.. (Sorry) | |
---|---|
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 long gBlockSize;␊ |
49 | static long 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 gBlockSize;␊ |
66 | static long gCaseSensitive;␊ |
67 | static long 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, uint64_t *length, void *base, uint64_t offset);␊ |
80 | static long GetCatalogEntryInfo(void *entry, long *flags, long *time,␊ |
81 | FinderInfo *finderInfo, long *infoValid);␊ |
82 | static long ResolvePathToCatalogEntry(char *filePath, long *flags,␊ |
83 | void *entry, long dirID, long *dirIndex);␊ |
84 | ␊ |
85 | static long GetCatalogEntry(long *dirIndex, char **name,␊ |
86 | long *flags, long *time,␊ |
87 | FinderInfo *finderInfo, long *infoValid);␊ |
88 | static long ReadCatalogEntry(char *fileName, long dirID, void *entry,␊ |
89 | long *dirIndex);␊ |
90 | static long ReadExtentsEntry(long fileID, long startBlock, void *entry);␊ |
91 | ␊ |
92 | static long ReadBTreeEntry(long btree, void *key, char *entry, long *dirIndex);␊ |
93 | static void GetBTreeRecord(long index, char *nodeBuffer, long nodeSize,␊ |
94 | char **key, char **data);␊ |
95 | ␊ |
96 | static long ReadExtent(char *extent, uint64_t extentSize, long extentFile,␊ |
97 | uint64_t offset, uint64_t size, void *buffer, long cache);␊ |
98 | ␊ |
99 | static long GetExtentStart(void *extents, long index);␊ |
100 | static long GetExtentSize(void *extents, long 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,␊ |
109 | u_int16_t *uniStr2, u_int32_t len2);␊ |
110 | ␊ |
111 | ␊ |
112 | static void SwapFinderInfo(FndrFileInfo *dst, FndrFileInfo *src)␊ |
113 | {␊ |
114 | dst->fdType = SWAP_BE32(src->fdType);␊ |
115 | dst->fdCreator = SWAP_BE32(src->fdCreator);␊ |
116 | dst->fdFlags = SWAP_BE16(src->fdFlags);␊ |
117 | // Don't bother with location␊ |
118 | }␊ |
119 | ␊ |
120 | void HFSFree(CICell ih)␊ |
121 | {␊ |
122 | if(gCurrentIH == ih)␊ |
123 | gCurrentIH = 0;␊ |
124 | free(ih);␊ |
125 | }␊ |
126 | ␊ |
127 | bool HFSProbe (const void *buf)␊ |
128 | {␊ |
129 | ␉const HFSMasterDirectoryBlock *mdb;␊ |
130 | ␉const HFSPlusVolumeHeader *header;␊ |
131 | ␉mdb=(const HFSMasterDirectoryBlock *)(((const char*)buf)+kMDBBaseOffset);␊ |
132 | ␉header=(const HFSPlusVolumeHeader *)(((const char*)buf)+kMDBBaseOffset);␊ |
133 | ␉␊ |
134 | ␉if ( SWAP_BE16(mdb->drSigWord) == kHFSSigWord )␊ |
135 | ␉␉return true;␊ |
136 | ␉if (SWAP_BE16(header->signature) != kHFSPlusSigWord &&␊ |
137 | SWAP_BE16(header->signature) != kHFSXSigWord)␊ |
138 | ␉␉return false;␊ |
139 | ␉return true;␊ |
140 | }␊ |
141 | ␊ |
142 | long HFSInitPartition(CICell ih)␊ |
143 | {␊ |
144 | long extentSize, extentFile, nodeSize;␊ |
145 | void *extent;␊ |
146 | ␊ |
147 | if (ih == gCurrentIH) {␊ |
148 | #ifdef __i386__␊ |
149 | CacheInit(ih, gCacheBlockSize);␊ |
150 | #endif␊ |
151 | return 0;␊ |
152 | }␊ |
153 | ␊ |
154 | #ifdef __i386__␊ |
155 | if (!gTempStr) gTempStr = (char *)malloc(4096);␊ |
156 | if (!gLinkTemp) gLinkTemp = (char *)malloc(64);␊ |
157 | if (!gBTreeHeaderBuffer) gBTreeHeaderBuffer = (char *)malloc(512);␊ |
158 | if (!gHFSMdbVib) {␊ |
159 | gHFSMdbVib = (char *)malloc(kBlockSize);␊ |
160 | gHFSMDB = (HFSMasterDirectoryBlock *)gHFSMdbVib;␊ |
161 | }␊ |
162 | if (!gHFSPlusHeader) {␊ |
163 | gHFSPlusHeader = (char *)malloc(kBlockSize);␊ |
164 | gHFSPlus = (HFSPlusVolumeHeader *)gHFSPlusHeader;␊ |
165 | }␊ |
166 | if (!gTempStr || !gLinkTemp || !gBTreeHeaderBuffer ||␊ |
167 | !gHFSMdbVib || !gHFSPlusHeader) return -1;␊ |
168 | #endif /* __i386__ */␊ |
169 | ␊ |
170 | gAllocationOffset = 0;␊ |
171 | gIsHFSPlus = 0;␊ |
172 | gCaseSensitive = 0;␊ |
173 | gBTHeaders[0] = 0;␊ |
174 | gBTHeaders[1] = 0;␊ |
175 | ␊ |
176 | // Look for the HFS MDB␊ |
177 | Seek(ih, kMDBBaseOffset);␊ |
178 | Read(ih, (long)gHFSMdbVib, kBlockSize);␊ |
179 | ␊ |
180 | if ( SWAP_BE16(gHFSMDB->drSigWord) == kHFSSigWord ) {␊ |
181 | gAllocationOffset = SWAP_BE16(gHFSMDB->drAlBlSt) * kBlockSize;␊ |
182 | ␊ |
183 | // See if it is HFSPlus␊ |
184 | if (SWAP_BE16(gHFSMDB->drEmbedSigWord) != kHFSPlusSigWord) {␊ |
185 | // Normal HFS;␊ |
186 | gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSMDB->drAlBlkSiz);␊ |
187 | CacheInit(ih, gCacheBlockSize);␊ |
188 | gCurrentIH = ih;␊ |
189 | ␊ |
190 | // grab the 64 bit volume ID␊ |
191 | bcopy(&gHFSMDB->drFndrInfo[6], &gVolID, 8);␊ |
192 | ␊ |
193 | // Get the Catalog BTree node size.␊ |
194 | extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;␊ |
195 | extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);␊ |
196 | extentFile = kHFSCatalogFileID;␊ |
197 | ReadExtent(extent, extentSize, extentFile, 0, 256,␊ |
198 | gBTreeHeaderBuffer + kBTreeCatalog * 256, 0);␊ |
199 | ␊ |
200 | nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 + ␊ |
201 | sizeof(BTNodeDescriptor)))->nodeSize);␊ |
202 | ␊ |
203 | // If the BTree node size is larger than the block size, reset the cache.␊ |
204 | if (nodeSize > gBlockSize) {␊ |
205 | gCacheBlockSize = nodeSize;␊ |
206 | CacheInit(ih, gCacheBlockSize);␊ |
207 | }␊ |
208 | ␊ |
209 | return 0;␊ |
210 | }␊ |
211 | ␊ |
212 | // Calculate the offset to the embeded HFSPlus volume.␊ |
213 | gAllocationOffset += (long long)SWAP_BE16(gHFSMDB->drEmbedExtent.startBlock) *␊ |
214 | SWAP_BE32(gHFSMDB->drAlBlkSiz);␊ |
215 | }␊ |
216 | ␊ |
217 | // Look for the HFSPlus Header␊ |
218 | Seek(ih, gAllocationOffset + kMDBBaseOffset);␊ |
219 | Read(ih, (long)gHFSPlusHeader, kBlockSize);␊ |
220 | ␊ |
221 | // Not a HFS+ or HFSX volume.␊ |
222 | if (SWAP_BE16(gHFSPlus->signature) != kHFSPlusSigWord &&␊ |
223 | SWAP_BE16(gHFSPlus->signature) != kHFSXSigWord) {␊ |
224 | ␉verbose("HFS signature was not present.\n");␊ |
225 | gCurrentIH = 0;␊ |
226 | ␉return -1;␊ |
227 | }␊ |
228 | ␊ |
229 | gIsHFSPlus = 1;␊ |
230 | gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSPlus->blockSize);␊ |
231 | CacheInit(ih, gCacheBlockSize);␊ |
232 | gCurrentIH = ih;␊ |
233 | ␊ |
234 | ␉ih->modTime = SWAP_BE32(gHFSPlus->modifyDate) - 2082844800;␊ |
235 | ␉␊ |
236 | // grab the 64 bit volume ID␊ |
237 | bcopy(&gHFSPlus->finderInfo[24], &gVolID, 8);␊ |
238 | ␊ |
239 | // Get the Catalog BTree node size.␊ |
240 | extent = &gHFSPlus->catalogFile.extents;␊ |
241 | extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);␊ |
242 | extentFile = kHFSCatalogFileID;␊ |
243 | ␊ |
244 | ReadExtent(extent, extentSize, extentFile, 0, 256,␊ |
245 | gBTreeHeaderBuffer + kBTreeCatalog * 256, 0);␊ |
246 | ␊ |
247 | nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 +␊ |
248 | sizeof(BTNodeDescriptor)))->nodeSize);␊ |
249 | ␊ |
250 | // If the BTree node size is larger than the block size, reset the cache.␊ |
251 | if (nodeSize > gBlockSize) {␊ |
252 | gCacheBlockSize = nodeSize;␊ |
253 | CacheInit(ih, gCacheBlockSize);␊ |
254 | }␊ |
255 | ␊ |
256 | return 0;␊ |
257 | }␊ |
258 | ␊ |
259 | long HFSLoadFile(CICell ih, char * filePath)␊ |
260 | {␊ |
261 | return HFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);␊ |
262 | }␊ |
263 | ␊ |
264 | long HFSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length)␊ |
265 | {␊ |
266 | char entry[512];␊ |
267 | long dirID, result, flags;␊ |
268 | ␊ |
269 | if (HFSInitPartition(ih) == -1) return -1;␊ |
270 | ␊ |
271 | dirID = kHFSRootFolderID;␊ |
272 | // Skip a lead '\'. Start in the system folder if there are two.␊ |
273 | if (filePath[0] == '/') {␊ |
274 | if (filePath[1] == '/') {␊ |
275 | if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);␊ |
276 | else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);␊ |
277 | if (dirID == 0) {␊ |
278 | ␉␉return -1;␊ |
279 | ␉ }␊ |
280 | filePath++;␊ |
281 | }␊ |
282 | filePath++;␊ |
283 | }␊ |
284 | ␊ |
285 | result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);␊ |
286 | if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) {␊ |
287 | ␉return -1;␊ |
288 | }␊ |
289 | ␊ |
290 | #if UNUSED␊ |
291 | // Not yet for Intel. System.config/Default.table will fail this check.␊ |
292 | // Check file owner and permissions.␊ |
293 | if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1;␊ |
294 | #endif␊ |
295 | ␊ |
296 | result = ReadFile(entry, &length, base, offset);␊ |
297 | if (result == -1) {␊ |
298 | ␉return -1;␊ |
299 | }␊ |
300 | ␊ |
301 | verbose("Loaded HFS%s file: [%s] %d bytes from %x.\n",␊ |
302 | (gIsHFSPlus ? "+" : ""), filePath, (uint32_t)length, ih);␊ |
303 | ␉␊ |
304 | return length;␊ |
305 | }␊ |
306 | ␊ |
307 | long HFSGetDirEntry(CICell ih, char * dirPath, long * dirIndex, char ** name,␊ |
308 | long * flags, long * time,␊ |
309 | FinderInfo * finderInfo, long * infoValid)␊ |
310 | {␊ |
311 | char entry[512];␊ |
312 | long dirID, dirFlags;␊ |
313 | ␊ |
314 | if (HFSInitPartition(ih) == -1) return -1;␊ |
315 | ␊ |
316 | if (*dirIndex == -1) return -1;␊ |
317 | ␊ |
318 | dirID = kHFSRootFolderID;␊ |
319 | // Skip a lead '\'. Start in the system folder if there are two.␊ |
320 | if (dirPath[0] == '/') {␊ |
321 | if (dirPath[1] == '/') {␊ |
322 | if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);␊ |
323 | else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);␊ |
324 | if (dirID == 0) return -1;␊ |
325 | dirPath++;␊ |
326 | }␊ |
327 | dirPath++;␊ |
328 | }␊ |
329 | ␊ |
330 | if (*dirIndex == 0) {␊ |
331 | ResolvePathToCatalogEntry(dirPath, &dirFlags, entry, dirID, dirIndex);␊ |
332 | if (*dirIndex == 0) *dirIndex = -1;␊ |
333 | if ((dirFlags & kFileTypeMask) != kFileTypeUnknown) return -1;␊ |
334 | }␊ |
335 | ␊ |
336 | GetCatalogEntry(dirIndex, name, flags, time, finderInfo, infoValid);␊ |
337 | if (*dirIndex == 0) *dirIndex = -1;␊ |
338 | if ((*flags & kFileTypeMask) == kFileTypeUnknown) return -1;␊ |
339 | ␊ |
340 | return 0;␊ |
341 | }␊ |
342 | ␊ |
343 | void␊ |
344 | HFSGetDescription(CICell ih, char *str, long strMaxLen)␊ |
345 | {␊ |
346 | ␊ |
347 | UInt16 nodeSize;␊ |
348 | UInt32 firstLeafNode;␊ |
349 | long dirIndex;␊ |
350 | char *name;␊ |
351 | long flags, time;␊ |
352 | ␊ |
353 | if (HFSInitPartition(ih) == -1) { return; }␊ |
354 | ␊ |
355 | /* Fill some crucial data structures by side effect. */␊ |
356 | dirIndex = 0;␊ |
357 | HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);␊ |
358 | ␊ |
359 | /* Now we can loook up the volume name node. */␊ |
360 | nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);␊ |
361 | firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);␊ |
362 | ␊ |
363 | dirIndex = firstLeafNode * nodeSize;␊ |
364 | ␊ |
365 | GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);␊ |
366 | ␊ |
367 | strncpy(str, name, strMaxLen);␊ |
368 | str[strMaxLen] = '\0';␊ |
369 | }␊ |
370 | ␊ |
371 | ␊ |
372 | long␊ |
373 | HFSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)␊ |
374 | {␊ |
375 | char entry[512];␊ |
376 | long dirID, result, flags;␊ |
377 | void *extents;␊ |
378 | HFSCatalogFile *hfsFile = (void *)entry;␊ |
379 | HFSPlusCatalogFile *hfsPlusFile = (void *)entry;␊ |
380 | ␊ |
381 | if (HFSInitPartition(ih) == -1) return -1;␊ |
382 | ␊ |
383 | dirID = kHFSRootFolderID;␊ |
384 | // Skip a lead '\'. Start in the system folder if there are two.␊ |
385 | if (filePath[0] == '/') {␊ |
386 | if (filePath[1] == '/') {␊ |
387 | if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);␊ |
388 | else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);␊ |
389 | if (dirID == 0) {␊ |
390 | ␉␉return -1;␊ |
391 | ␉ }␊ |
392 | filePath++;␊ |
393 | }␊ |
394 | filePath++;␊ |
395 | }␊ |
396 | ␊ |
397 | result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);␊ |
398 | if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) {␊ |
399 | printf("HFS: Resolve path %s failed\n", filePath);␊ |
400 | ␉return -1;␊ |
401 | }␊ |
402 | ␊ |
403 | if (gIsHFSPlus) {␊ |
404 | extents = &hfsPlusFile->dataFork.extents;␊ |
405 | } else {␊ |
406 | extents = &hfsFile->dataExtents;␊ |
407 | }␊ |
408 | ␊ |
409 | #if DEBUG␊ |
410 | printf("extent start 0x%x\n", (unsigned long)GetExtentStart(extents, 0));␊ |
411 | printf("block size 0x%x\n", (unsigned long)gBlockSize);␊ |
412 | printf("Allocation offset 0x%x\n", (unsigned long)gAllocationOffset);␊ |
413 | #endif␊ |
414 | *firstBlock = ((unsigned long long)GetExtentStart(extents, 0) * (unsigned long long) gBlockSize + gAllocationOffset) / 512ULL;␊ |
415 | return 0;␊ |
416 | }␊ |
417 | ␊ |
418 | long HFSGetUUID(CICell ih, char *uuidStr)␊ |
419 | {␊ |
420 | if (HFSInitPartition(ih) == -1) return -1;␊ |
421 | if (gVolID == 0LL) return -1;␊ |
422 | ␊ |
423 | return CreateUUIDString((uint8_t*)(&gVolID), sizeof(gVolID), uuidStr);␊ |
424 | }␊ |
425 | ␊ |
426 | // Private Functions␊ |
427 | ␊ |
428 | static long ReadFile(void * file, uint64_t * length, void * base, uint64_t offset)␊ |
429 | {␊ |
430 | void *extents;␊ |
431 | long fileID;␊ |
432 | uint64_t fileLength;␊ |
433 | HFSCatalogFile *hfsFile = file;␊ |
434 | HFSPlusCatalogFile *hfsPlusFile = file;␊ |
435 | ␊ |
436 | if (gIsHFSPlus) {␊ |
437 | fileID = SWAP_BE32(hfsPlusFile->fileID);␊ |
438 | fileLength = (uint64_t)SWAP_BE64(hfsPlusFile->dataFork.logicalSize);␊ |
439 | extents = &hfsPlusFile->dataFork.extents;␊ |
440 | } else {␊ |
441 | fileID = SWAP_BE32(hfsFile->fileID);␊ |
442 | fileLength = SWAP_BE32(hfsFile->dataLogicalSize);␊ |
443 | extents = &hfsFile->dataExtents;␊ |
444 | }␊ |
445 | ␊ |
446 | if (offset > fileLength) {␊ |
447 | printf("Offset is too large.\n");␊ |
448 | return -1;␊ |
449 | }␊ |
450 | ␊ |
451 | if ((*length == 0) || ((offset + *length) > fileLength)) {␊ |
452 | *length = fileLength - offset;␊ |
453 | }␊ |
454 | ␊ |
455 | /* if (*length > kLoadSize) {␊ |
456 | printf("File is too large.\n");␊ |
457 | return -1;␊ |
458 | }*/␊ |
459 | ␊ |
460 | *length = ReadExtent((char *)extents, fileLength, fileID,␊ |
461 | offset, *length, (char *)base, 0);␊ |
462 | ␊ |
463 | return 0;␊ |
464 | }␊ |
465 | ␊ |
466 | static long GetCatalogEntryInfo(void * entry, long * flags, long * time,␊ |
467 | FinderInfo * finderInfo, long * infoValid)␊ |
468 | {␊ |
469 | long tmpTime = 0;␊ |
470 | long valid = 0;␊ |
471 | ␊ |
472 | // Get information about the file.␊ |
473 | ␊ |
474 | switch ( SWAP_BE16(*(short *)entry) )␊ |
475 | {␊ |
476 | case kHFSFolderRecord :␊ |
477 | *flags = kFileTypeDirectory;␊ |
478 | tmpTime = SWAP_BE32(((HFSCatalogFolder *)entry)->modifyDate);␊ |
479 | break;␊ |
480 | ␊ |
481 | case kHFSPlusFolderRecord :␊ |
482 | *flags = kFileTypeDirectory |␊ |
483 | (SWAP_BE16(((HFSPlusCatalogFolder *)entry)->bsdInfo.fileMode) & kPermMask);␊ |
484 | if (SWAP_BE32(((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID) != 0)␊ |
485 | *flags |= kOwnerNotRoot;␊ |
486 | tmpTime = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->contentModDate);␊ |
487 | break;␊ |
488 | ␊ |
489 | case kHFSFileRecord :␊ |
490 | *flags = kFileTypeFlat;␊ |
491 | tmpTime = SWAP_BE32(((HFSCatalogFile *)entry)->modifyDate);␊ |
492 | if (finderInfo) {␊ |
493 | SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSCatalogFile *)entry)->userInfo);␊ |
494 | valid = 1;␊ |
495 | }␊ |
496 | break;␊ |
497 | ␊ |
498 | case kHFSPlusFileRecord :␊ |
499 | *flags = kFileTypeFlat |␊ |
500 | (SWAP_BE16(((HFSPlusCatalogFile *)entry)->bsdInfo.fileMode) & kPermMask);␊ |
501 | if (SWAP_BE32(((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID) != 0)␊ |
502 | *flags |= kOwnerNotRoot;␊ |
503 | tmpTime = SWAP_BE32(((HFSPlusCatalogFile *)entry)->contentModDate);␊ |
504 | if (finderInfo) {␊ |
505 | SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSPlusCatalogFile *)entry)->userInfo);␊ |
506 | valid = 1;␊ |
507 | }␊ |
508 | break;␊ |
509 | ␊ |
510 | case kHFSFileThreadRecord :␊ |
511 | case kHFSPlusFileThreadRecord :␊ |
512 | case kHFSFolderThreadRecord :␊ |
513 | case kHFSPlusFolderThreadRecord :␊ |
514 | *flags = kFileTypeUnknown;␊ |
515 | tmpTime = 0;␊ |
516 | break;␊ |
517 | }␊ |
518 | ␊ |
519 | if (time != 0) {␊ |
520 | // Convert base time from 1904 to 1970.␊ |
521 | *time = tmpTime - 2082844800;␊ |
522 | }␊ |
523 | if (infoValid) *infoValid = valid;␊ |
524 | ␊ |
525 | return 0;␊ |
526 | }␊ |
527 | ␊ |
528 | static long ResolvePathToCatalogEntry(char * filePath, long * flags,␊ |
529 | void * entry, long dirID, long * dirIndex)␊ |
530 | {␊ |
531 | char *restPath;␊ |
532 | long result, cnt, subFolderID = 0, tmpDirIndex;␊ |
533 | HFSPlusCatalogFile *hfsPlusFile;␊ |
534 | ␊ |
535 | // Copy the file name to gTempStr␊ |
536 | cnt = 0;␊ |
537 | while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++;␊ |
538 | strlcpy(gTempStr, filePath, cnt+1);␊ |
539 | ␊ |
540 | // Move restPath to the right place.␊ |
541 | if (filePath[cnt] != '\0') cnt++;␊ |
542 | restPath = filePath + cnt;␊ |
543 | ␊ |
544 | // gTempStr is a name in the current Dir.␊ |
545 | // restPath is the rest of the path if any.␊ |
546 | ␊ |
547 | result = ReadCatalogEntry(gTempStr, dirID, entry, dirIndex);␊ |
548 | if (result == -1) {␊ |
549 | ␉return -1;␊ |
550 | }␊ |
551 | ␊ |
552 | GetCatalogEntryInfo(entry, flags, 0, 0, 0);␊ |
553 | ␊ |
554 | if ((*flags & kFileTypeMask) == kFileTypeDirectory) {␊ |
555 | if (gIsHFSPlus)␊ |
556 | subFolderID = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->folderID);␊ |
557 | else␊ |
558 | subFolderID = SWAP_BE32(((HFSCatalogFolder *)entry)->folderID);␊ |
559 | }␊ |
560 | ␊ |
561 | if ((*flags & kFileTypeMask) == kFileTypeDirectory)␊ |
562 | result = ResolvePathToCatalogEntry(restPath, flags, entry,␊ |
563 | subFolderID, dirIndex);␊ |
564 | ␊ |
565 | if (gIsHFSPlus && ((*flags & kFileTypeMask) == kFileTypeFlat)) {␊ |
566 | hfsPlusFile = (HFSPlusCatalogFile *)entry;␊ |
567 | if ((SWAP_BE32(hfsPlusFile->userInfo.fdType) == kHardLinkFileType) &&␊ |
568 | (SWAP_BE32(hfsPlusFile->userInfo.fdCreator) == kHFSPlusCreator)) {␊ |
569 | sprintf(gLinkTemp, "%s/%s%ld", HFSPLUSMETADATAFOLDER,␊ |
570 | HFS_INODE_PREFIX, SWAP_BE32(hfsPlusFile->bsdInfo.special.iNodeNum));␊ |
571 | result = ResolvePathToCatalogEntry(gLinkTemp, flags, entry,␊ |
572 | kHFSRootFolderID, &tmpDirIndex);␊ |
573 | }␊ |
574 | }␊ |
575 | ␊ |
576 | return result;␊ |
577 | }␊ |
578 | ␊ |
579 | static long GetCatalogEntry(long * dirIndex, char ** name,␊ |
580 | long * flags, long * time,␊ |
581 | FinderInfo * finderInfo, long * infoValid)␊ |
582 | {␊ |
583 | long extentSize, nodeSize, curNode, index;␊ |
584 | void *extent;␊ |
585 | char *nodeBuf, *testKey, *entry;␊ |
586 | BTNodeDescriptor *node;␊ |
587 | ␊ |
588 | if (gIsHFSPlus) {␊ |
589 | extent = &gHFSPlus->catalogFile.extents;␊ |
590 | extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);␊ |
591 | } else {␊ |
592 | extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;␊ |
593 | extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);␊ |
594 | }␊ |
595 | ␊ |
596 | nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);␊ |
597 | nodeBuf = (char *)malloc(nodeSize);␊ |
598 | node = (BTNodeDescriptor *)nodeBuf;␊ |
599 | ␊ |
600 | index = *dirIndex % nodeSize;␊ |
601 | curNode = *dirIndex / nodeSize;␊ |
602 | ␊ |
603 | // Read the BTree node and get the record for index.␊ |
604 | ReadExtent(extent, extentSize, kHFSCatalogFileID,␊ |
605 | (long long)curNode * nodeSize, nodeSize, nodeBuf, 1);␊ |
606 | GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);␊ |
607 | ␊ |
608 | GetCatalogEntryInfo(entry, flags, time, finderInfo, infoValid);␊ |
609 | ␊ |
610 | // Get the file name.␊ |
611 | if (gIsHFSPlus) {␊ |
612 | utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,␊ |
613 | SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),␊ |
614 | (u_int8_t *)gTempStr, 256, OSBigEndian);␊ |
615 | } else {␊ |
616 | strncpy(gTempStr,␊ |
617 | (const char *)&((HFSCatalogKey *)testKey)->nodeName[1],␊ |
618 | ((HFSCatalogKey *)testKey)->nodeName[0]);␊ |
619 | gTempStr[((HFSCatalogKey *)testKey)->nodeName[0]] = '\0';␊ |
620 | }␊ |
621 | *name = gTempStr;␊ |
622 | ␊ |
623 | // Update dirIndex.␊ |
624 | index++;␊ |
625 | if (index == SWAP_BE16(node->numRecords)) {␊ |
626 | index = 0;␊ |
627 | curNode = SWAP_BE32(node->fLink);␊ |
628 | }␊ |
629 | *dirIndex = curNode * nodeSize + index;␊ |
630 | ␊ |
631 | free(nodeBuf);␊ |
632 | ␊ |
633 | return 0;␊ |
634 | }␊ |
635 | ␊ |
636 | static long ReadCatalogEntry(char * fileName, long dirID,␊ |
637 | void * entry, long * dirIndex)␊ |
638 | {␊ |
639 | long length;␊ |
640 | char key[sizeof(HFSPlusCatalogKey)];␊ |
641 | HFSCatalogKey *hfsKey = (HFSCatalogKey *)key;␊ |
642 | HFSPlusCatalogKey *hfsPlusKey = (HFSPlusCatalogKey *)key;␊ |
643 | ␊ |
644 | // Make the catalog key.␊ |
645 | if ( gIsHFSPlus )␊ |
646 | {␊ |
647 | hfsPlusKey->parentID = SWAP_BE32(dirID);␊ |
648 | length = strlen(fileName);␊ |
649 | if (length > 255) length = 255;␊ |
650 | utf_decodestr((u_int8_t *)fileName, hfsPlusKey->nodeName.unicode,␊ |
651 | &(hfsPlusKey->nodeName.length), 512, OSBigEndian);␊ |
652 | } else {␊ |
653 | hfsKey->parentID = SWAP_BE32(dirID);␊ |
654 | length = strlen(fileName);␊ |
655 | if (length > 31) length = 31;␊ |
656 | hfsKey->nodeName[0] = length;␊ |
657 | strncpy((char *)(hfsKey->nodeName + 1), fileName, length);␊ |
658 | }␊ |
659 | ␊ |
660 | return ReadBTreeEntry(kBTreeCatalog, &key, entry, dirIndex);␊ |
661 | }␊ |
662 | ␊ |
663 | static long ReadExtentsEntry(long fileID, long startBlock, void * entry)␊ |
664 | {␊ |
665 | char key[sizeof(HFSPlusExtentKey)];␊ |
666 | HFSExtentKey *hfsKey = (HFSExtentKey *)key;␊ |
667 | HFSPlusExtentKey *hfsPlusKey = (HFSPlusExtentKey *)key;␊ |
668 | ␊ |
669 | // Make the extents key.␊ |
670 | if (gIsHFSPlus) {␊ |
671 | hfsPlusKey->forkType = 0;␊ |
672 | hfsPlusKey->fileID = SWAP_BE32(fileID);␊ |
673 | hfsPlusKey->startBlock = SWAP_BE32(startBlock);␊ |
674 | } else {␊ |
675 | hfsKey->forkType = 0;␊ |
676 | hfsKey->fileID = SWAP_BE32(fileID);␊ |
677 | hfsKey->startBlock = SWAP_BE16(startBlock);␊ |
678 | }␊ |
679 | ␊ |
680 | return ReadBTreeEntry(kBTreeExtents, &key, entry, 0);␊ |
681 | }␊ |
682 | ␊ |
683 | static long ReadBTreeEntry(long btree, void * key, char * entry, long * dirIndex)␊ |
684 | {␊ |
685 | long extentSize;␊ |
686 | void *extent;␊ |
687 | short extentFile;␊ |
688 | char *nodeBuf;␊ |
689 | BTNodeDescriptor *node;␊ |
690 | long nodeSize, result = 0, entrySize = 0;␊ |
691 | long curNode, index = 0, lowerBound, upperBound;␊ |
692 | char *testKey, *recordData;␊ |
693 | ␊ |
694 | // Figure out which tree is being looked at.␊ |
695 | if (btree == kBTreeCatalog) {␊ |
696 | if (gIsHFSPlus) {␊ |
697 | extent = &gHFSPlus->catalogFile.extents;␊ |
698 | extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);␊ |
699 | } else {␊ |
700 | extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;␊ |
701 | extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);␊ |
702 | }␊ |
703 | extentFile = kHFSCatalogFileID;␊ |
704 | } else {␊ |
705 | if (gIsHFSPlus) {␊ |
706 | extent = &gHFSPlus->extentsFile.extents;␊ |
707 | extentSize = SWAP_BE64(gHFSPlus->extentsFile.logicalSize);␊ |
708 | } else {␊ |
709 | extent = (HFSExtentDescriptor *)&gHFSMDB->drXTExtRec;␊ |
710 | extentSize = SWAP_BE32(gHFSMDB->drXTFlSize);␊ |
711 | }␊ |
712 | extentFile = kHFSExtentsFileID;␊ |
713 | }␊ |
714 | ␊ |
715 | // Read the BTree Header if needed.␊ |
716 | if (gBTHeaders[btree] == 0) {␊ |
717 | ReadExtent(extent, extentSize, extentFile, 0, 256,␊ |
718 | gBTreeHeaderBuffer + btree * 256, 0);␊ |
719 | gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 +␊ |
720 | sizeof(BTNodeDescriptor));␊ |
721 | if ((gIsHFSPlus && btree == kBTreeCatalog) &&␊ |
722 | (gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare)) {␊ |
723 | gCaseSensitive = 1;␊ |
724 | }␊ |
725 | }␊ |
726 | ␊ |
727 | curNode = SWAP_BE32(gBTHeaders[btree]->rootNode);␊ |
728 | nodeSize = SWAP_BE16(gBTHeaders[btree]->nodeSize);␊ |
729 | nodeBuf = (char *)malloc(nodeSize);␊ |
730 | node = (BTNodeDescriptor *)nodeBuf;␊ |
731 | ␊ |
732 | while (1) {␊ |
733 | // Read the current node.␊ |
734 | ReadExtent(extent, extentSize, extentFile,␊ |
735 | (long long)curNode * nodeSize, nodeSize, nodeBuf, 1);␊ |
736 | ␊ |
737 | // Find the matching key.␊ |
738 | lowerBound = 0;␊ |
739 | upperBound = SWAP_BE16(node->numRecords) - 1;␊ |
740 | while (lowerBound <= upperBound) {␊ |
741 | index = (lowerBound + upperBound) / 2;␊ |
742 | ␊ |
743 | GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);␊ |
744 | ␊ |
745 | if (gIsHFSPlus) {␊ |
746 | if (btree == kBTreeCatalog) {␊ |
747 | result = CompareHFSPlusCatalogKeys(key, testKey);␊ |
748 | } else {␊ |
749 | result = CompareHFSPlusExtentsKeys(key, testKey);␊ |
750 | }␊ |
751 | } else {␊ |
752 | if (btree == kBTreeCatalog) {␊ |
753 | result = CompareHFSCatalogKeys(key, testKey);␊ |
754 | } else {␊ |
755 | result = CompareHFSExtentsKeys(key, testKey);␊ |
756 | }␊ |
757 | }␊ |
758 | ␊ |
759 | if (result < 0) upperBound = index - 1; // search < trial␊ |
760 | else if (result > 0) lowerBound = index + 1; // search > trial␊ |
761 | else break; // search = trial␊ |
762 | }␊ |
763 | ␊ |
764 | if (result < 0) {␊ |
765 | index = upperBound;␊ |
766 | GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);␊ |
767 | }␊ |
768 | ␊ |
769 | // Found the closest key... Recurse on it if this is an index node.␊ |
770 | if (node->kind == kBTIndexNode) {␊ |
771 | curNode = SWAP_BE32( *((long *)recordData) );␊ |
772 | } else break;␊ |
773 | }␊ |
774 | ␊ |
775 | // Return error if the file was not found.␊ |
776 | if (result != 0) { free(nodeBuf); return -1; }␊ |
777 | ␊ |
778 | if (btree == kBTreeCatalog) {␊ |
779 | switch (SWAP_BE16(*(short *)recordData)) {␊ |
780 | case kHFSFolderRecord : entrySize = 70; break;␊ |
781 | case kHFSFileRecord : entrySize = 102; break;␊ |
782 | case kHFSFolderThreadRecord : entrySize = 46; break;␊ |
783 | case kHFSFileThreadRecord : entrySize = 46; break;␊ |
784 | case kHFSPlusFolderRecord : entrySize = 88; break;␊ |
785 | case kHFSPlusFileRecord : entrySize = 248; break;␊ |
786 | case kHFSPlusFolderThreadRecord : entrySize = 264; break;␊ |
787 | case kHFSPlusFileThreadRecord : entrySize = 264; break;␊ |
788 | }␊ |
789 | } else {␊ |
790 | if (gIsHFSPlus) entrySize = sizeof(HFSPlusExtentRecord);␊ |
791 | else entrySize = sizeof(HFSExtentRecord);␊ |
792 | }␊ |
793 | ␊ |
794 | bcopy(recordData, entry, entrySize);␊ |
795 | ␊ |
796 | // Update dirIndex.␊ |
797 | if (dirIndex != 0) {␊ |
798 | index++;␊ |
799 | if (index == SWAP_BE16(node->numRecords)) {␊ |
800 | index = 0;␊ |
801 | curNode = SWAP_BE32(node->fLink);␊ |
802 | }␊ |
803 | *dirIndex = curNode * nodeSize + index;␊ |
804 | }␊ |
805 | ␊ |
806 | free(nodeBuf);␊ |
807 | ␊ |
808 | return 0;␊ |
809 | }␊ |
810 | ␊ |
811 | static void GetBTreeRecord(long index, char * nodeBuffer, long nodeSize,␊ |
812 | char ** key, char ** data)␊ |
813 | {␊ |
814 | long keySize;␊ |
815 | long recordOffset;␊ |
816 | ␊ |
817 | recordOffset = SWAP_BE16(*((short *)(nodeBuffer + (nodeSize - 2 * index - 2))));␊ |
818 | *key = nodeBuffer + recordOffset;␊ |
819 | if (gIsHFSPlus) {␊ |
820 | keySize = SWAP_BE16(*(short *)*key);␊ |
821 | *data = *key + 2 + keySize;␊ |
822 | } else {␊ |
823 | keySize = **key;␊ |
824 | *data = *key + 2 + keySize - (keySize & 1);␊ |
825 | }␊ |
826 | }␊ |
827 | ␊ |
828 | static long ReadExtent(char * extent, uint64_t extentSize,␊ |
829 | long extentFile, uint64_t offset, uint64_t size,␊ |
830 | void * buffer, long cache)␊ |
831 | {␊ |
832 | uint64_t lastOffset;␊ |
833 | ␉long long blockNumber, countedBlocks = 0;␊ |
834 | long long nextExtent = 0, sizeRead = 0, readSize;␊ |
835 | long long nextExtentBlock, currentExtentBlock = 0;␊ |
836 | long long readOffset;␊ |
837 | long long extentDensity, sizeofExtent, currentExtentSize;␊ |
838 | char *currentExtent, *extentBuffer = 0, *bufferPos = buffer;␊ |
839 | ␊ |
840 | if (offset >= extentSize) return 0;␊ |
841 | ␊ |
842 | if (gIsHFSPlus) {␊ |
843 | extentDensity = kHFSPlusExtentDensity;␊ |
844 | sizeofExtent = sizeof(HFSPlusExtentDescriptor);␊ |
845 | } else {␊ |
846 | extentDensity = kHFSExtentDensity;␊ |
847 | sizeofExtent = sizeof(HFSExtentDescriptor);␊ |
848 | }␊ |
849 | ␊ |
850 | lastOffset = offset + size;␊ |
851 | while (offset < lastOffset) {␊ |
852 | blockNumber = offset / gBlockSize;␊ |
853 | ␊ |
854 | // Find the extent for the offset.␊ |
855 | for (; ; nextExtent++) {␊ |
856 | if (nextExtent < extentDensity) {␊ |
857 | if ((countedBlocks+GetExtentSize(extent, nextExtent)-1)<blockNumber) {␊ |
858 | countedBlocks += GetExtentSize(extent, nextExtent);␊ |
859 | continue;␊ |
860 | }␊ |
861 | ␊ |
862 | currentExtent = extent + nextExtent * sizeofExtent;␊ |
863 | break;␊ |
864 | }␊ |
865 | ␊ |
866 | if (extentBuffer == 0) {␊ |
867 | extentBuffer = malloc(sizeofExtent * extentDensity);␊ |
868 | if (extentBuffer == 0) return -1;␊ |
869 | }␊ |
870 | ␊ |
871 | nextExtentBlock = nextExtent / extentDensity;␊ |
872 | if (currentExtentBlock != nextExtentBlock) {␊ |
873 | ReadExtentsEntry(extentFile, countedBlocks, extentBuffer);␊ |
874 | currentExtentBlock = nextExtentBlock;␊ |
875 | }␊ |
876 | ␊ |
877 | currentExtentSize = GetExtentSize(extentBuffer, nextExtent % extentDensity);␊ |
878 | ␊ |
879 | if ((countedBlocks + currentExtentSize - 1) >= blockNumber) {␊ |
880 | currentExtent = extentBuffer + sizeofExtent * (nextExtent % extentDensity);␊ |
881 | break;␊ |
882 | }␊ |
883 | ␊ |
884 | countedBlocks += currentExtentSize;␊ |
885 | }␊ |
886 | ␊ |
887 | readOffset = ((blockNumber - countedBlocks) * gBlockSize) +␊ |
888 | (offset % gBlockSize);␊ |
889 | ␊ |
890 | ␉␉// MacWen: fix overflow in multiplication by forcing 64bit multiplication␊ |
891 | readSize = (long long)GetExtentSize(currentExtent, 0) * gBlockSize - readOffset;␊ |
892 | if (readSize > (size - sizeRead)) readSize = size - sizeRead;␊ |
893 | ␊ |
894 | readOffset += (long long)GetExtentStart(currentExtent, 0) * gBlockSize;␊ |
895 | ␊ |
896 | CacheRead(gCurrentIH, bufferPos, gAllocationOffset + readOffset,␊ |
897 | readSize, cache);␊ |
898 | ␊ |
899 | sizeRead += readSize;␊ |
900 | offset += readSize;␊ |
901 | bufferPos += readSize;␊ |
902 | }␊ |
903 | ␊ |
904 | if (extentBuffer) free(extentBuffer);␊ |
905 | ␊ |
906 | return sizeRead;␊ |
907 | }␊ |
908 | ␊ |
909 | static long GetExtentStart(void * extents, long index)␊ |
910 | {␊ |
911 | long start;␊ |
912 | HFSExtentDescriptor *hfsExtents = extents;␊ |
913 | HFSPlusExtentDescriptor *hfsPlusExtents = extents;␊ |
914 | ␊ |
915 | if (gIsHFSPlus) start = SWAP_BE32(hfsPlusExtents[index].startBlock);␊ |
916 | else start = SWAP_BE16(hfsExtents[index].startBlock);␊ |
917 | ␊ |
918 | return start;␊ |
919 | }␊ |
920 | ␊ |
921 | static long GetExtentSize(void * extents, long index)␊ |
922 | {␊ |
923 | long size;␊ |
924 | HFSExtentDescriptor *hfsExtents = extents;␊ |
925 | HFSPlusExtentDescriptor *hfsPlusExtents = extents;␊ |
926 | ␊ |
927 | if (gIsHFSPlus) size = SWAP_BE32(hfsPlusExtents[index].blockCount);␊ |
928 | else size = SWAP_BE16(hfsExtents[index].blockCount);␊ |
929 | ␊ |
930 | return size;␊ |
931 | }␊ |
932 | ␊ |
933 | static long CompareHFSCatalogKeys(void * key, void * testKey)␊ |
934 | {␊ |
935 | HFSCatalogKey *searchKey, *trialKey;␊ |
936 | long result, searchParentID, trialParentID;␊ |
937 | ␊ |
938 | searchKey = key;␊ |
939 | trialKey = testKey;␊ |
940 | ␊ |
941 | searchParentID = SWAP_BE32(searchKey->parentID);␊ |
942 | trialParentID = SWAP_BE32(trialKey->parentID);␊ |
943 | ␊ |
944 | // parent dirID is unsigned␊ |
945 | if (searchParentID > trialParentID) result = 1;␊ |
946 | else if (searchParentID < trialParentID) result = -1;␊ |
947 | else {␊ |
948 | // parent dirID's are equal, compare names␊ |
949 | result = FastRelString(searchKey->nodeName, trialKey->nodeName);␊ |
950 | }␊ |
951 | ␊ |
952 | return result;␊ |
953 | }␊ |
954 | ␊ |
955 | static long CompareHFSPlusCatalogKeys(void * key, void * testKey)␊ |
956 | {␊ |
957 | HFSPlusCatalogKey *searchKey, *trialKey;␊ |
958 | long result, searchParentID, trialParentID;␊ |
959 | ␊ |
960 | searchKey = key;␊ |
961 | trialKey = testKey;␊ |
962 | ␊ |
963 | searchParentID = SWAP_BE32(searchKey->parentID);␊ |
964 | trialParentID = SWAP_BE32(trialKey->parentID);␊ |
965 | ␊ |
966 | // parent dirID is unsigned␊ |
967 | if (searchParentID > trialParentID) result = 1;␊ |
968 | else if (searchParentID < trialParentID) result = -1;␊ |
969 | else {␊ |
970 | // parent dirID's are equal, compare names␊ |
971 | if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0))␊ |
972 | result = searchKey->nodeName.length - trialKey->nodeName.length;␊ |
973 | else␊ |
974 | if (gCaseSensitive) {␊ |
975 | result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0],␊ |
976 | SWAP_BE16(searchKey->nodeName.length),␊ |
977 | &trialKey->nodeName.unicode[0],␊ |
978 | SWAP_BE16(trialKey->nodeName.length));␊ |
979 | } else {␊ |
980 | result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],␊ |
981 | SWAP_BE16(searchKey->nodeName.length),␊ |
982 | &trialKey->nodeName.unicode[0],␊ |
983 | SWAP_BE16(trialKey->nodeName.length), OSBigEndian);␊ |
984 | }␊ |
985 | }␊ |
986 | ␊ |
987 | return result;␊ |
988 | }␊ |
989 | ␊ |
990 | static long CompareHFSExtentsKeys(void * key, void * testKey)␊ |
991 | {␊ |
992 | HFSExtentKey *searchKey, *trialKey;␊ |
993 | long result;␊ |
994 | ␊ |
995 | searchKey = key;␊ |
996 | trialKey = testKey;␊ |
997 | ␊ |
998 | // assume searchKey < trialKey␊ |
999 | result = -1; ␊ |
1000 | ␊ |
1001 | if (searchKey->fileID == trialKey->fileID) {␊ |
1002 | // FileNum's are equal; compare fork types␊ |
1003 | if (searchKey->forkType == trialKey->forkType) {␊ |
1004 | // Fork types are equal; compare allocation block number␊ |
1005 | if (searchKey->startBlock == trialKey->startBlock) {␊ |
1006 | // Everything is equal␊ |
1007 | result = 0;␊ |
1008 | } else {␊ |
1009 | // Allocation block numbers differ; determine sign␊ |
1010 | if (SWAP_BE16(searchKey->startBlock) > SWAP_BE16(trialKey->startBlock))␊ |
1011 | result = 1;␊ |
1012 | }␊ |
1013 | } else {␊ |
1014 | // Fork types differ; determine sign␊ |
1015 | if (searchKey->forkType > trialKey->forkType) result = 1;␊ |
1016 | }␊ |
1017 | } else {␊ |
1018 | // FileNums differ; determine sign␊ |
1019 | if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))␊ |
1020 | result = 1;␊ |
1021 | }␊ |
1022 | ␊ |
1023 | return result;␊ |
1024 | }␊ |
1025 | ␊ |
1026 | static long CompareHFSPlusExtentsKeys(void * key, void * testKey)␊ |
1027 | {␊ |
1028 | HFSPlusExtentKey *searchKey, *trialKey;␊ |
1029 | long result;␊ |
1030 | ␊ |
1031 | searchKey = key;␊ |
1032 | trialKey = testKey;␊ |
1033 | ␊ |
1034 | // assume searchKey < trialKey␊ |
1035 | result = -1; ␊ |
1036 | ␊ |
1037 | if (searchKey->fileID == trialKey->fileID) {␊ |
1038 | // FileNum's are equal; compare fork types␊ |
1039 | if (searchKey->forkType == trialKey->forkType) {␊ |
1040 | // Fork types are equal; compare allocation block number␊ |
1041 | if (searchKey->startBlock == trialKey->startBlock) {␊ |
1042 | // Everything is equal␊ |
1043 | result = 0;␊ |
1044 | } else {␊ |
1045 | // Allocation block numbers differ; determine sign␊ |
1046 | if (SWAP_BE32(searchKey->startBlock) > SWAP_BE32(trialKey->startBlock))␊ |
1047 | result = 1;␊ |
1048 | }␊ |
1049 | } else {␊ |
1050 | // Fork types differ; determine sign␊ |
1051 | if (searchKey->forkType > trialKey->forkType) result = 1;␊ |
1052 | }␊ |
1053 | } else {␊ |
1054 | // FileNums differ; determine sign␊ |
1055 | if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))␊ |
1056 | result = 1;␊ |
1057 | }␊ |
1058 | ␊ |
1059 | return result;␊ |
1060 | }␊ |
1061 | ␊ |
1062 |