Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/libsaio/hfs.c

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

Archive Download this file

Revision: 2636