Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/libsaio/hfs.c

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
44static CICell gCurrentIH;
45static long long gAllocationOffset;
46static long gIsHFSPlus;
47static long gCaseSensitive;
48static long gBlockSize;
49static long gCacheBlockSize;
50static char *gBTreeHeaderBuffer;
51static BTHeaderRec *gBTHeaders[2];
52static char *gHFSMdbVib;
53static HFSMasterDirectoryBlock *gHFSMDB;
54static char *gHFSPlusHeader;
55static HFSPlusVolumeHeader *gHFSPlus;
56static char *gLinkTemp;
57static long long gVolID;
58static char *gTempStr;
59
60#else /* !__i386__ */
61
62static CICell gCurrentIH;
63static long long gAllocationOffset;
64static long gIsHFSPlus;
65static long gBlockSize;
66static long gCaseSensitive;
67static long gCacheBlockSize;
68static char gBTreeHeaderBuffer[512];
69static BTHeaderRec *gBTHeaders[2];
70static char gHFSMdbVib[kBlockSize];
71static HFSMasterDirectoryBlock *gHFSMDB =(HFSMasterDirectoryBlock*)gHFSMdbVib;
72static char gHFSPlusHeader[kBlockSize];
73static HFSPlusVolumeHeader *gHFSPlus =(HFSPlusVolumeHeader*)gHFSPlusHeader;
74static char gLinkTemp[64];
75static long long gVolID;
76
77#endif /* !__i386__ */
78
79static long ReadFile(void *file, uint64_t *length, void *base, uint64_t offset);
80static long GetCatalogEntryInfo(void *entry, long *flags, long *time,
81 FinderInfo *finderInfo, long *infoValid);
82static long ResolvePathToCatalogEntry(char *filePath, long *flags,
83 void *entry, long dirID, long *dirIndex);
84
85static long GetCatalogEntry(long *dirIndex, char **name,
86 long *flags, long *time,
87 FinderInfo *finderInfo, long *infoValid);
88static long ReadCatalogEntry(char *fileName, long dirID, void *entry,
89 long *dirIndex);
90static long ReadExtentsEntry(long fileID, long startBlock, void *entry);
91
92static long ReadBTreeEntry(long btree, void *key, char *entry, long *dirIndex);
93static void GetBTreeRecord(long index, char *nodeBuffer, long nodeSize,
94 char **key, char **data);
95
96static long ReadExtent(char *extent, uint64_t extentSize, long extentFile,
97 uint64_t offset, uint64_t size, void *buffer, long cache);
98
99static long GetExtentStart(void *extents, long index);
100static long GetExtentSize(void *extents, long index);
101
102static long CompareHFSCatalogKeys(void *key, void *testKey);
103static long CompareHFSPlusCatalogKeys(void *key, void *testKey);
104static long CompareHFSExtentsKeys(void *key, void *testKey);
105static long CompareHFSPlusExtentsKeys(void *key, void *testKey);
106
107extern long FastRelString(u_int8_t *str1, u_int8_t *str2);
108extern long BinaryUnicodeCompare(u_int16_t *uniStr1, u_int32_t len1,
109 u_int16_t *uniStr2, u_int32_t len2);
110
111
112static 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
120void HFSFree(CICell ih)
121{
122 if(gCurrentIH == ih)
123 gCurrentIH = 0;
124 free(ih);
125}
126
127bool HFSProbe (const void *buf)
128{
129const HFSMasterDirectoryBlock *mdb;
130const HFSPlusVolumeHeader *header;
131mdb=(const HFSMasterDirectoryBlock *)(((const char*)buf)+kMDBBaseOffset);
132header=(const HFSPlusVolumeHeader *)(((const char*)buf)+kMDBBaseOffset);
133
134if ( SWAP_BE16(mdb->drSigWord) == kHFSSigWord )
135return true;
136if (SWAP_BE16(header->signature) != kHFSPlusSigWord &&
137 SWAP_BE16(header->signature) != kHFSXSigWord)
138return false;
139return true;
140}
141
142long 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) {
224verbose("HFS signature was not present.\n");
225 gCurrentIH = 0;
226return -1;
227 }
228
229 gIsHFSPlus = 1;
230 gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSPlus->blockSize);
231 CacheInit(ih, gCacheBlockSize);
232 gCurrentIH = ih;
233
234ih->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
259long HFSLoadFile(CICell ih, char * filePath)
260{
261 return HFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);
262}
263
264long 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) {
278return -1;
279 }
280 filePath++;
281 }
282 filePath++;
283 }
284
285 result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);
286 if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
287return -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) {
298return -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
307long 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
343void
344HFSGetDescription(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
372long
373HFSGetFileBlock(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) {
390return -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);
400return -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
418long 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
428static 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
466static 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
528static 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) {
549return -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
579static 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
636static 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
663static 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
683static 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
811static 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
828static 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;
833long 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
909static 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
921static 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
933static 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
955static 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
990static 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
1026static 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

Archive Download this file

Revision: 284