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;
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%c): 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;
650}
651
652if (time != 0)
653{
654// Convert base time from 1904 to 1970.
655*time = tmpTime - 2082844800;
656}
657
658if (infoValid)
659{
660*infoValid = valid;
661}
662
663return 0;
664}
665
666//==============================================================================
667
668static long ResolvePathToCatalogEntry(char * filePath, long * flags, void * entry, u_int32_t dirID, long long * dirIndex)
669{
670char*restPath;
671longresult, cnt;
672u_int32_tsubFolderID = 0;
673long longtmpDirIndex;
674HFSPlusCatalogFile*hfsPlusFile;
675
676// Copy the file name to gTempStr
677cnt = 0;
678while ((filePath[cnt] != '/') && (filePath[cnt] != '\0'))
679{
680cnt++;
681}
682
683strlcpy(gTempStr, filePath, cnt+1);
684
685// Move restPath to the right place.
686if (filePath[cnt] != '\0')
687{
688cnt++;
689}
690
691restPath = filePath + cnt;
692
693// gTempStr is a name in the current Dir.
694// restPath is the rest of the path if any.
695
696result = ReadCatalogEntry(gTempStr, dirID, entry, dirIndex);
697
698if (result == -1)
699{
700return -1;
701}
702
703GetCatalogEntryInfo(entry, flags, 0, 0, 0);
704
705if ((*flags & kFileTypeMask) == kFileTypeDirectory)
706{
707if (gIsHFSPlus)
708{
709subFolderID = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->folderID);
710}
711else
712{
713subFolderID = SWAP_BE32(((HFSCatalogFolder *)entry)->folderID);
714}
715}
716
717if ((*flags & kFileTypeMask) == kFileTypeDirectory)
718{
719result = ResolvePathToCatalogEntry(restPath, flags, entry, subFolderID, dirIndex);
720}
721
722if (gIsHFSPlus && ((*flags & kFileTypeMask) == kFileTypeFlat))
723{
724hfsPlusFile = (HFSPlusCatalogFile *)entry;
725
726if ((SWAP_BE32(hfsPlusFile->userInfo.fdType) == kHardLinkFileType) && (SWAP_BE32(hfsPlusFile->userInfo.fdCreator) == kHFSPlusCreator))
727{
728sprintf(gLinkTemp, "%s/%s%ld", HFSPLUSMETADATAFOLDER, HFS_INODE_PREFIX, SWAP_BE32(hfsPlusFile->bsdInfo.special.iNodeNum));
729result = ResolvePathToCatalogEntry(gLinkTemp, flags, entry, kHFSRootFolderID, &tmpDirIndex);
730}
731}
732
733return result;
734}
735
736//==============================================================================
737
738static long GetCatalogEntry(long long * dirIndex, char ** name, long * flags, u_int32_t * time, FinderInfo * finderInfo, long * infoValid)
739{
740u_int64_t extentSize;
741void *extent;
742char *nodeBuf, *testKey, *entry;
743BTNodeDescriptor *node;
744u_int32_t curNode;
745u_int16_t nodeSize, index;
746
747if (gIsHFSPlus)
748{
749extent = &gHFSPlus->catalogFile.extents;
750extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);
751}
752else
753{
754extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;
755extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);
756}
757
758nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
759nodeBuf = (char *)malloc(nodeSize);
760node = (BTNodeDescriptor *)nodeBuf;
761
762index = (u_int16_t) (*dirIndex % nodeSize);
763curNode = (u_int32_t) (*dirIndex / nodeSize);
764
765// Read the BTree node and get the record for index.
766ReadExtent(extent, extentSize, kHFSCatalogFileID, (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
767
768GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);
769
770GetCatalogEntryInfo(entry, flags, time, finderInfo, infoValid);
771
772// Get the file name.
773if (gIsHFSPlus)
774{
775utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,
776 SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),
777 (u_int8_t *)gTempStr, 256, OSBigEndian);
778}
779else
780{
781strncpy(gTempStr, (const char *)&((HFSCatalogKey *)testKey)->nodeName[1], ((HFSCatalogKey *)testKey)->nodeName[0]);
782
783gTempStr[((HFSCatalogKey *)testKey)->nodeName[0]] = '\0';
784}
785*name = gTempStr;
786
787// Update dirIndex.
788index++;
789
790if (index == SWAP_BE16(node->numRecords))
791{
792index = 0;
793curNode = SWAP_BE32(node->fLink);
794}
795*dirIndex = (long long) curNode * nodeSize + index;
796
797free(nodeBuf);
798
799return 0;
800}
801
802//==============================================================================
803
804static long ReadCatalogEntry(char * fileName, u_int32_t dirID, void * entry, long long * dirIndex)
805{
806long length = strlen(fileName);
807char key[sizeof(HFSPlusCatalogKey)];
808HFSCatalogKey *hfsKey = (HFSCatalogKey *)key;
809HFSPlusCatalogKey *hfsPlusKey = (HFSPlusCatalogKey *)key;
810
811// Make the catalog key.
812if ( gIsHFSPlus )
813{
814if (length > kHFSPlusMaxFileNameChars)
815{
816length = kHFSPlusMaxFileNameChars;
817}
818
819hfsPlusKey->parentID = SWAP_BE32(dirID);
820
821utf_decodestr((u_int8_t *)fileName, hfsPlusKey->nodeName.unicode, &(hfsPlusKey->nodeName.length), 512, OSBigEndian);
822}
823else
824{
825if (length > kHFSMaxFileNameChars)
826{
827length = kHFSMaxFileNameChars;
828}
829
830hfsKey->parentID = SWAP_BE32(dirID);
831
832hfsKey->nodeName[0] = length;
833strncpy((char *)(hfsKey->nodeName + 1), fileName, length);
834}
835
836return ReadBTreeEntry(kBTreeCatalog, &key, entry, dirIndex);
837}
838
839//==============================================================================
840
841static long ReadExtentsEntry(u_int32_t fileID, long startBlock, void * entry)
842{
843char key[sizeof(HFSPlusExtentKey)];
844HFSExtentKey *hfsKey = (HFSExtentKey *)key;
845HFSPlusExtentKey *hfsPlusKey = (HFSPlusExtentKey *)key;
846
847// Make the extents key.
848if (gIsHFSPlus)
849{
850hfsPlusKey->forkType = 0;
851hfsPlusKey->fileID = SWAP_BE32(fileID);
852hfsPlusKey->startBlock = SWAP_BE32(startBlock);
853}
854else
855{
856hfsKey->forkType = 0;
857hfsKey->fileID = SWAP_BE32(fileID);
858hfsKey->startBlock = SWAP_BE16(startBlock);
859}
860
861return ReadBTreeEntry(kBTreeExtents, &key, entry, 0);
862}
863
864//==============================================================================
865
866static long ReadBTreeEntry(long btree, void * key, char * entry, long long * dirIndex)
867{
868u_int64_t extentSize;
869void *extent;
870u_int16_t extentFile;
871char *nodeBuf;
872BTNodeDescriptor *node;
873long result = 0, entrySize = 0;
874u_int32_t curNode;
875char *testKey, *recordData;
876u_int16_t nodeSize, index = 0, lowerBound, upperBound;
877
878// Figure out which tree is being looked at.
879if (btree == kBTreeCatalog)
880{
881if (gIsHFSPlus)
882{
883extent = &gHFSPlus->catalogFile.extents;
884extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);
885}
886else
887{
888extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;
889extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);
890}
891extentFile = kHFSCatalogFileID;
892}
893else
894{
895if (gIsHFSPlus)
896{
897extent = &gHFSPlus->extentsFile.extents;
898extentSize = SWAP_BE64(gHFSPlus->extentsFile.logicalSize);
899}
900else
901{
902extent = (HFSExtentDescriptor *)&gHFSMDB->drXTExtRec;
903extentSize = SWAP_BE32(gHFSMDB->drXTFlSize);
904}
905extentFile = kHFSExtentsFileID;
906}
907
908// Read the BTree Header if needed.
909if (gBTHeaders[btree] == 0)
910{
911ReadExtent(extent, extentSize, extentFile, 0, 256, gBTreeHeaderBuffer + btree * 256, 0);
912gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 + sizeof(BTNodeDescriptor));
913
914if ((gIsHFSPlus && btree == kBTreeCatalog) && (gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare))
915{
916gCaseSensitive = 1;
917}
918}
919
920curNode = SWAP_BE32(gBTHeaders[btree]->rootNode);
921nodeSize = SWAP_BE16(gBTHeaders[btree]->nodeSize);
922nodeBuf = (char *)malloc(nodeSize);
923node = (BTNodeDescriptor *)nodeBuf;
924
925while (1)
926{
927// Read the current node.
928 ReadExtent(extent, extentSize, extentFile, (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
929
930// Find the matching key.
931lowerBound = 0;
932upperBound = SWAP_BE16(node->numRecords) - 1;
933
934while (lowerBound <= upperBound)
935{
936index = (lowerBound + upperBound) / 2;
937
938GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);
939
940if (gIsHFSPlus)
941{
942if (btree == kBTreeCatalog)
943{
944result = CompareHFSPlusCatalogKeys(key, testKey);
945}
946else
947{
948result = CompareHFSPlusExtentsKeys(key, testKey);
949}
950}
951else
952{
953if (btree == kBTreeCatalog)
954{
955result = CompareHFSCatalogKeys(key, testKey);
956}
957else
958{
959result = CompareHFSExtentsKeys(key, testKey);
960}
961}
962
963if (result < 0)
964{
965upperBound = index - 1;// search < trial
966}
967else if (result > 0)
968{
969lowerBound = index + 1;// search > trial
970}
971else
972{
973break;// search = trial
974}
975}
976
977if (result < 0)
978{
979index = upperBound;
980GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);
981}
982
983// Found the closest key... Recurse on it if this is an index node.
984if (node->kind == kBTIndexNode)
985{
986curNode = SWAP_BE32( *((long *)recordData) );
987}
988else
989{
990break;
991}
992}
993
994// Return error if the file was not found.
995if (result != 0)
996{
997free(nodeBuf);
998return -1;
999}
1000
1001if (btree == kBTreeCatalog)
1002{
1003switch (SWAP_BE16(*(short *)recordData))
1004{
1005case kHFSFolderRecord : entrySize = 70;
1006break;
1007case kHFSFileRecord : entrySize = 102;
1008break;
1009case kHFSFolderThreadRecord : entrySize = 46;
1010break;
1011case kHFSFileThreadRecord : entrySize = 46;
1012break;
1013case kHFSPlusFolderRecord : entrySize = 88;
1014break;
1015case kHFSPlusFileRecord : entrySize = 248;
1016break;
1017case kHFSPlusFolderThreadRecord : entrySize = 264;
1018break;
1019case kHFSPlusFileThreadRecord : entrySize = 264;
1020break;
1021}
1022}
1023else
1024{
1025if (gIsHFSPlus)
1026{
1027entrySize = sizeof(HFSPlusExtentRecord);
1028}
1029else
1030{
1031entrySize = sizeof(HFSExtentRecord);
1032}
1033}
1034
1035bcopy(recordData, entry, entrySize);
1036
1037// Update dirIndex.
1038if (dirIndex != 0)
1039{
1040index++;
1041if (index == SWAP_BE16(node->numRecords))
1042{
1043index = 0;
1044curNode = SWAP_BE32(node->fLink);
1045}
1046*dirIndex = (long long) curNode * nodeSize + index;
1047}
1048
1049free(nodeBuf);
1050
1051return 0;
1052}
1053
1054//==============================================================================
1055
1056static void GetBTreeRecord(u_int16_t index, char * nodeBuffer, u_int16_t nodeSize, char ** key, char ** data)
1057{
1058u_int16_t recordOffset, keySize;
1059
1060recordOffset = SWAP_BE16(*((u_int16_t *)(nodeBuffer + (nodeSize - 2 * index - 2))));
1061*key = nodeBuffer + recordOffset;
1062
1063if (gIsHFSPlus)
1064{
1065keySize = SWAP_BE16(*(u_int16_t *)*key);
1066*data = *key + 2 + keySize;
1067}
1068else
1069{
1070keySize = **key;
1071*data = *key + 2 + keySize - (keySize & 1);
1072}
1073}
1074
1075//==============================================================================
1076
1077static long ReadExtent(char * extent, u_int64_t extentSize, u_int32_t extentFile, u_int64_t offset, u_int64_t size, void * buffer, long cache)
1078{
1079u_int64_t lastOffset;
1080u_int64_t blockNumber, countedBlocks = 0;
1081u_int64_t nextExtent = 0, sizeRead = 0, readSize;
1082u_int64_t nextExtentBlock, currentExtentBlock = 0;
1083u_int64_t readOffset;
1084u_int64_t extentDensity, sizeofExtent, currentExtentSize;
1085char *currentExtent, *extentBuffer = 0, *bufferPos = buffer;
1086
1087if (offset >= extentSize)
1088{
1089return 0;
1090}
1091
1092if (gIsHFSPlus)
1093{
1094extentDensity = kHFSPlusExtentDensity;
1095sizeofExtent = sizeof(HFSPlusExtentDescriptor);
1096}
1097else
1098{
1099extentDensity = kHFSExtentDensity;
1100sizeofExtent = sizeof(HFSExtentDescriptor);
1101}
1102
1103lastOffset = offset + size;
1104
1105while (offset < lastOffset)
1106{
1107blockNumber = offset / gBlockSize;
1108
1109// Find the extent for the offset.
1110for (; ; nextExtent++)
1111{
1112if (nextExtent < extentDensity)
1113{
1114if ((countedBlocks + GetExtentSize(extent, nextExtent) -1) < blockNumber)
1115{
1116countedBlocks += GetExtentSize(extent, nextExtent);
1117continue;
1118}
1119
1120currentExtent = extent + nextExtent * sizeofExtent;
1121break;
1122}
1123
1124if (extentBuffer == 0)
1125{
1126extentBuffer = malloc(sizeofExtent * extentDensity);
1127
1128if (extentBuffer == 0)
1129{
1130return -1;
1131}
1132}
1133
1134nextExtentBlock = nextExtent / extentDensity;
1135
1136if (currentExtentBlock != nextExtentBlock)
1137{
1138ReadExtentsEntry(extentFile, countedBlocks, extentBuffer);
1139currentExtentBlock = nextExtentBlock;
1140}
1141
1142currentExtentSize = GetExtentSize(extentBuffer, nextExtent % extentDensity);
1143
1144if ((countedBlocks + currentExtentSize - 1) >= blockNumber)
1145{
1146currentExtent = extentBuffer + sizeofExtent * (nextExtent % extentDensity);
1147break;
1148}
1149
1150countedBlocks += currentExtentSize;
1151}
1152
1153readOffset = ((blockNumber - countedBlocks) * gBlockSize) + (offset % gBlockSize);
1154
1155// MacWen: fix overflow in multiplication by forcing 64bit multiplication
1156readSize = (long long)GetExtentSize(currentExtent, 0) * gBlockSize - readOffset;
1157
1158if (readSize > (size - sizeRead))
1159{
1160readSize = size - sizeRead;
1161}
1162
1163readOffset += (long long)GetExtentStart(currentExtent, 0) * gBlockSize;
1164
1165CacheRead(gCurrentIH, bufferPos, gAllocationOffset + readOffset, readSize, cache);
1166
1167sizeRead += readSize;
1168offset += readSize;
1169bufferPos += readSize;
1170}
1171
1172if (extentBuffer)
1173{
1174free(extentBuffer);
1175}
1176
1177return sizeRead;
1178}
1179
1180//==============================================================================
1181
1182static u_int32_t GetExtentStart(void * extents, u_int32_t index)
1183{
1184u_int32_t start;
1185
1186HFSExtentDescriptor*hfsExtents= extents;
1187HFSPlusExtentDescriptor*hfsPlusExtents= extents;
1188
1189if (gIsHFSPlus)
1190{
1191start = SWAP_BE32(hfsPlusExtents[index].startBlock);
1192}
1193else
1194{
1195start = SWAP_BE16(hfsExtents[index].startBlock);
1196}
1197
1198return start;
1199}
1200
1201//==============================================================================
1202
1203static u_int32_t GetExtentSize(void * extents, u_int32_t index)
1204{
1205u_int32_t size = 0;
1206
1207HFSExtentDescriptor *hfsExtents = extents;
1208HFSPlusExtentDescriptor *hfsPlusExtents = extents;
1209
1210if (gIsHFSPlus)
1211{
1212size = SWAP_BE32(hfsPlusExtents[index].blockCount);
1213}
1214else
1215{
1216size = SWAP_BE16(hfsExtents[index].blockCount);
1217}
1218
1219return size;
1220}
1221
1222//==============================================================================
1223
1224static long CompareHFSCatalogKeys(void * key, void * testKey)
1225{
1226HFSCatalogKey *searchKey, *trialKey;
1227long result, searchParentID, trialParentID;
1228
1229searchKey = key;
1230trialKey = testKey;
1231
1232searchParentID = SWAP_BE32(searchKey->parentID);
1233trialParentID = SWAP_BE32(trialKey->parentID);
1234
1235// parent dirID is unsigned
1236if (searchParentID > trialParentID)
1237{
1238result = 1;
1239}
1240else if (searchParentID < trialParentID)
1241{
1242result = -1;
1243}
1244else
1245{
1246// parent dirID's are equal, compare names
1247result = FastRelString(searchKey->nodeName, trialKey->nodeName);
1248}
1249
1250return result;
1251}
1252
1253//==============================================================================
1254
1255static long CompareHFSPlusCatalogKeys(void * key, void * testKey)
1256{
1257HFSPlusCatalogKey *searchKey, *trialKey;
1258long result, searchParentID, trialParentID;
1259
1260searchKey = key;
1261trialKey = testKey;
1262
1263searchParentID = SWAP_BE32(searchKey->parentID);
1264trialParentID = SWAP_BE32(trialKey->parentID);
1265
1266// parent dirID is unsigned
1267if (searchParentID > trialParentID)
1268{
1269result = 1;
1270}
1271else if (searchParentID < trialParentID)
1272{
1273result = -1;
1274}
1275else
1276{
1277// parent dirID's are equal, compare names
1278if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0))
1279{
1280result = searchKey->nodeName.length - trialKey->nodeName.length;
1281}
1282else if (gCaseSensitive)
1283{
1284result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0],
1285 SWAP_BE16(searchKey->nodeName.length),
1286 &trialKey->nodeName.unicode[0],
1287 SWAP_BE16(trialKey->nodeName.length));
1288}
1289else
1290{
1291result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],
1292 SWAP_BE16(searchKey->nodeName.length),
1293 &trialKey->nodeName.unicode[0],
1294 SWAP_BE16(trialKey->nodeName.length), OSBigEndian);
1295}
1296}
1297
1298return result;
1299}
1300
1301//==============================================================================
1302
1303static long CompareHFSExtentsKeys(void * key, void * testKey)
1304{
1305HFSExtentKey *searchKey, *trialKey;
1306long result;
1307
1308searchKey = key;
1309trialKey = testKey;
1310
1311// assume searchKey < trialKey
1312result = -1;
1313
1314if (searchKey->fileID == trialKey->fileID)
1315{
1316// FileNum's are equal; compare fork types
1317if (searchKey->forkType == trialKey->forkType)
1318{
1319// Fork types are equal; compare allocation block number
1320if (searchKey->startBlock == trialKey->startBlock)
1321{
1322// Everything is equal
1323result = 0;
1324}
1325else
1326{
1327// Allocation block numbers differ; determine sign
1328if (SWAP_BE16(searchKey->startBlock) > SWAP_BE16(trialKey->startBlock))
1329{
1330result = 1;
1331}
1332}
1333 }
1334else
1335{
1336// Fork types differ; determine sign
1337if (searchKey->forkType > trialKey->forkType)
1338{
1339result = 1;
1340}
1341}
1342}
1343else
1344{
1345// FileNums differ; determine sign
1346if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))
1347{
1348result = 1;
1349}
1350}
1351
1352return result;
1353}
1354
1355
1356//==============================================================================
1357
1358static long CompareHFSPlusExtentsKeys(void * key, void * testKey)
1359{
1360HFSPlusExtentKey*searchKey, *trialKey;
1361
1362longresult;
1363
1364searchKey = key;
1365trialKey = testKey;
1366
1367// assume searchKey < trialKey
1368result = -1;
1369
1370if (searchKey->fileID == trialKey->fileID)
1371{
1372// FileNum's are equal; compare fork types
1373if (searchKey->forkType == trialKey->forkType)
1374{
1375// Fork types are equal; compare allocation block number
1376if (searchKey->startBlock == trialKey->startBlock)
1377{
1378// Everything is equal
1379result = 0;
1380}
1381else
1382{
1383// Allocation block numbers differ; determine sign
1384if (SWAP_BE32(searchKey->startBlock) > SWAP_BE32(trialKey->startBlock))
1385{
1386result = 1;
1387}
1388}
1389}
1390else
1391{
1392// Fork types differ; determine sign
1393if (searchKey->forkType > trialKey->forkType)
1394{
1395result = 1;
1396}
1397}
1398}
1399else
1400{
1401// FileNums differ; determine sign
1402if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))
1403{
1404result = 1;
1405}
1406}
1407
1408 return result;
1409}
1410
1411

Archive Download this file

Revision: 2538