Chameleon

Chameleon Svn Source Tree

Root/branches/Bungo/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{
446 verbose("HFSGetDescription: Init partition failed");
447return;
448}
449
450/* Fill some crucial data structures by side effect. */
451HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
452
453/* Now we can loook up the volume name node. */
454nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
455firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
456
457dirIndex = (long long)firstLeafNode * nodeSize;
458
459GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
460
461strncpy(str, name, strMaxLen);
462str[strMaxLen] = '\0';
463 //verbose("HFS: label=%s\n", str);
464}
465
466//==============================================================================
467
468long HFSGetFileBlock(CICell ih, char *filePath, u_int64_t *firstBlock)
469{
470char entry[512];
471long result, flags;
472u_int32_t dirID;
473void *extents;
474HFSCatalogFile *hfsFile = (void *)entry;
475HFSPlusCatalogFile *hfsPlusFile = (void *)entry;
476
477if (HFSInitPartition(ih) == -1)
478{
479return -1;
480}
481
482dirID = kHFSRootFolderID;
483// Skip a lead '/'. Start in the system folder if there are two.
484if (filePath[0] == '/')
485{
486if (filePath[1] == '/')
487{
488if (gIsHFSPlus)
489{
490dirID = SWAP_BE32(((long *) gHFSPlus->finderInfo)[5]);
491}
492else
493{
494dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);
495}
496
497if (dirID == 0)
498{
499return -1;
500}
501filePath++;
502}
503filePath++;
504}
505
506result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);
507
508if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
509{
510verbose("HFSGetFileBlock: Resolve path '%s' failed\n", filePath);
511return -1;
512}
513
514if (gIsHFSPlus) {
515extents = &hfsPlusFile->dataFork.extents;
516} else {
517extents = &hfsFile->dataExtents;
518}
519
520#if DEBUG
521printf("extent start 0x%x\n", GetExtentStart(extents, 0));
522printf("block size 0x%x\n", gBlockSize);
523printf("Allocation offset 0x%x\n", (unsigned long)gAllocationOffset);
524#endif
525*firstBlock = ((u_int64_t) GetExtentStart(extents, 0) * (u_int64_t) gBlockSize + gAllocationOffset) / 512ULL;
526return 0;
527}
528
529
530//==============================================================================
531
532long HFSGetUUID(CICell ih, char *uuidStr)
533{
534if (HFSInitPartition(ih) == -1)
535{
536return -1;
537}
538
539if (gVolID == 0LL)
540{
541return -1;
542}
543
544return CreateUUIDString((uint8_t*)(&gVolID), sizeof(gVolID), uuidStr);
545}
546
547//==============================================================================
548// Private Functions
549
550static long ReadFile(void * file, u_int64_t * length, void * base, u_int64_t offset)
551{
552u_int64_t fileLength;
553void *extents;
554HFSCatalogFile *hfsFile = file;
555HFSPlusCatalogFile *hfsPlusFile = file;
556u_int32_t fileID;
557
558if (gIsHFSPlus)
559{
560fileID = SWAP_BE32(hfsPlusFile->fileID);
561fileLength = (uint64_t)SWAP_BE64(hfsPlusFile->dataFork.logicalSize);
562extents = &hfsPlusFile->dataFork.extents;
563}
564else
565{
566fileID = SWAP_BE32(hfsFile->fileID);
567fileLength = SWAP_BE32(hfsFile->dataLogicalSize);
568extents = &hfsFile->dataExtents;
569}
570
571if (offset > fileLength)
572{
573verbose("ReadFile(HFS%c): Offset is too large.\n", gIsHFSPlus ? "+" : "");
574
575return -1;
576}
577
578if ((*length == 0) || ((offset + *length) > fileLength))
579{
580*length = fileLength - offset;
581}
582
583/*
584if (*length > kLoadSize)
585{
586printf("File is too large.\n");
587return -1;
588}
589*/
590
591*length = ReadExtent((char *)extents, fileLength, fileID, offset, *length, (char *)base, 0);
592
593return 0;
594}
595
596//==============================================================================
597
598static long GetCatalogEntryInfo(void * entry, long * flags, u_int32_t * time, FinderInfo * finderInfo, long * infoValid)
599{
600u_int32_t tmpTime = 0;
601long valid = 0;
602
603// Get information about the file.
604
605switch ( SWAP_BE16(*(short *)entry) )
606{
607case kHFSFolderRecord :
608*flags = kFileTypeDirectory;
609tmpTime = SWAP_BE32(((HFSCatalogFolder *)entry)->modifyDate);
610break;
611
612case kHFSPlusFolderRecord :
613*flags = kFileTypeDirectory | (SWAP_BE16(((HFSPlusCatalogFolder *)entry)->bsdInfo.fileMode) & kPermMask);
614if (SWAP_BE32(((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID) != 0)
615{
616*flags |= kOwnerNotRoot;
617}
618tmpTime = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->contentModDate);
619break;
620
621case kHFSFileRecord :
622*flags = kFileTypeFlat;
623tmpTime = SWAP_BE32(((HFSCatalogFile *)entry)->modifyDate);
624if (finderInfo)
625{
626SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSCatalogFile *)entry)->userInfo);
627valid = 1;
628}
629break;
630
631case kHFSPlusFileRecord :
632*flags = kFileTypeFlat | (SWAP_BE16(((HFSPlusCatalogFile *)entry)->bsdInfo.fileMode) & kPermMask);
633if (SWAP_BE32(((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID) != 0)
634{
635*flags |= kOwnerNotRoot;
636}
637tmpTime = SWAP_BE32(((HFSPlusCatalogFile *)entry)->contentModDate);
638if (finderInfo)
639{
640SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSPlusCatalogFile *)entry)->userInfo);
641valid = 1;
642}
643break;
644
645case kHFSFileThreadRecord :
646case kHFSPlusFileThreadRecord :
647case kHFSFolderThreadRecord :
648case kHFSPlusFolderThreadRecord :
649*flags = kFileTypeUnknown;
650tmpTime = 0;
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%ld", 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);
925node = (BTNodeDescriptor *)nodeBuf;
926
927while (1)
928{
929// Read the current node.
930 ReadExtent(extent, extentSize, extentFile, (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
931
932// Find the matching key.
933lowerBound = 0;
934upperBound = SWAP_BE16(node->numRecords) - 1;
935
936while (lowerBound <= upperBound)
937{
938index = (lowerBound + upperBound) / 2;
939
940GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);
941
942if (gIsHFSPlus)
943{
944if (btree == kBTreeCatalog)
945{
946result = CompareHFSPlusCatalogKeys(key, testKey);
947}
948else
949{
950result = CompareHFSPlusExtentsKeys(key, testKey);
951}
952}
953else
954{
955if (btree == kBTreeCatalog)
956{
957result = CompareHFSCatalogKeys(key, testKey);
958}
959else
960{
961result = CompareHFSExtentsKeys(key, testKey);
962}
963}
964
965if (result < 0)
966{
967upperBound = index - 1;// search < trial
968}
969else if (result > 0)
970{
971lowerBound = index + 1;// search > trial
972}
973else
974{
975break;// search = trial
976}
977}
978
979if (result < 0)
980{
981index = upperBound;
982GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);
983}
984
985// Found the closest key... Recurse on it if this is an index node.
986if (node->kind == kBTIndexNode)
987{
988curNode = SWAP_BE32( *((long *)recordData) );
989}
990else
991{
992break;
993}
994}
995
996// Return error if the file was not found.
997if (result != 0)
998{
999free(nodeBuf);
1000return -1;
1001}
1002
1003if (btree == kBTreeCatalog)
1004{
1005switch (SWAP_BE16(*(short *)recordData))
1006{
1007case kHFSFolderRecord : entrySize = 70;
1008break;
1009case kHFSFileRecord : entrySize = 102;
1010break;
1011case kHFSFolderThreadRecord : entrySize = 46;
1012break;
1013case kHFSFileThreadRecord : entrySize = 46;
1014break;
1015case kHFSPlusFolderRecord : entrySize = 88;
1016break;
1017case kHFSPlusFileRecord : entrySize = 248;
1018break;
1019case kHFSPlusFolderThreadRecord : entrySize = 264;
1020break;
1021case kHFSPlusFileThreadRecord : entrySize = 264;
1022break;
1023}
1024}
1025else
1026{
1027if (gIsHFSPlus)
1028{
1029entrySize = sizeof(HFSPlusExtentRecord);
1030}
1031else
1032{
1033entrySize = sizeof(HFSExtentRecord);
1034}
1035}
1036
1037bcopy(recordData, entry, entrySize);
1038
1039// Update dirIndex.
1040if (dirIndex != 0)
1041{
1042index++;
1043if (index == SWAP_BE16(node->numRecords))
1044{
1045index = 0;
1046curNode = SWAP_BE32(node->fLink);
1047}
1048*dirIndex = (long long) curNode * nodeSize + index;
1049}
1050
1051free(nodeBuf);
1052
1053return 0;
1054}
1055
1056//==============================================================================
1057
1058static void GetBTreeRecord(u_int16_t index, char * nodeBuffer, u_int16_t nodeSize, char ** key, char ** data)
1059{
1060u_int16_t recordOffset, keySize;
1061
1062recordOffset = SWAP_BE16(*((u_int16_t *)(nodeBuffer + (nodeSize - 2 * index - 2))));
1063*key = nodeBuffer + recordOffset;
1064
1065if (gIsHFSPlus)
1066{
1067keySize = SWAP_BE16(*(u_int16_t *)*key);
1068*data = *key + 2 + keySize;
1069}
1070else
1071{
1072keySize = **key;
1073*data = *key + 2 + keySize - (keySize & 1);
1074}
1075}
1076
1077//==============================================================================
1078
1079static long ReadExtent(char * extent, u_int64_t extentSize, u_int32_t extentFile, u_int64_t offset, u_int64_t size, void * buffer, long cache)
1080{
1081u_int64_t lastOffset;
1082u_int64_t blockNumber, countedBlocks = 0;
1083u_int64_t nextExtent = 0, sizeRead = 0, readSize;
1084u_int64_t nextExtentBlock, currentExtentBlock = 0;
1085u_int64_t readOffset;
1086u_int64_t extentDensity, sizeofExtent, currentExtentSize;
1087char *currentExtent, *extentBuffer = 0, *bufferPos = buffer;
1088
1089if (offset >= extentSize)
1090{
1091return 0;
1092}
1093
1094if (gIsHFSPlus)
1095{
1096extentDensity = kHFSPlusExtentDensity;
1097sizeofExtent = sizeof(HFSPlusExtentDescriptor);
1098}
1099else
1100{
1101extentDensity = kHFSExtentDensity;
1102sizeofExtent = sizeof(HFSExtentDescriptor);
1103}
1104
1105lastOffset = offset + size;
1106
1107while (offset < lastOffset)
1108{
1109blockNumber = offset / gBlockSize;
1110
1111// Find the extent for the offset.
1112for (; ; nextExtent++)
1113{
1114if (nextExtent < extentDensity)
1115{
1116if ((countedBlocks + GetExtentSize(extent, nextExtent) -1) < blockNumber)
1117{
1118countedBlocks += GetExtentSize(extent, nextExtent);
1119continue;
1120}
1121
1122currentExtent = extent + nextExtent * sizeofExtent;
1123break;
1124}
1125
1126if (extentBuffer == 0)
1127{
1128extentBuffer = malloc(sizeofExtent * extentDensity);
1129
1130if (extentBuffer == 0)
1131{
1132return -1;
1133}
1134}
1135
1136nextExtentBlock = nextExtent / extentDensity;
1137
1138if (currentExtentBlock != nextExtentBlock)
1139{
1140ReadExtentsEntry(extentFile, countedBlocks, extentBuffer);
1141currentExtentBlock = nextExtentBlock;
1142}
1143
1144currentExtentSize = GetExtentSize(extentBuffer, nextExtent % extentDensity);
1145
1146if ((countedBlocks + currentExtentSize - 1) >= blockNumber)
1147{
1148currentExtent = extentBuffer + sizeofExtent * (nextExtent % extentDensity);
1149break;
1150}
1151
1152countedBlocks += currentExtentSize;
1153}
1154
1155readOffset = ((blockNumber - countedBlocks) * gBlockSize) + (offset % gBlockSize);
1156
1157// MacWen: fix overflow in multiplication by forcing 64bit multiplication
1158readSize = (long long)GetExtentSize(currentExtent, 0) * gBlockSize - readOffset;
1159
1160if (readSize > (size - sizeRead))
1161{
1162readSize = size - sizeRead;
1163}
1164
1165readOffset += (long long)GetExtentStart(currentExtent, 0) * gBlockSize;
1166
1167CacheRead(gCurrentIH, bufferPos, gAllocationOffset + readOffset, readSize, cache);
1168
1169sizeRead += readSize;
1170offset += readSize;
1171bufferPos += readSize;
1172}
1173
1174if (extentBuffer)
1175{
1176free(extentBuffer);
1177}
1178
1179return sizeRead;
1180}
1181
1182//==============================================================================
1183
1184static u_int32_t GetExtentStart(void * extents, u_int32_t index)
1185{
1186u_int32_t start;
1187
1188HFSExtentDescriptor*hfsExtents= extents;
1189HFSPlusExtentDescriptor*hfsPlusExtents= extents;
1190
1191if (gIsHFSPlus)
1192{
1193start = SWAP_BE32(hfsPlusExtents[index].startBlock);
1194}
1195else
1196{
1197start = SWAP_BE16(hfsExtents[index].startBlock);
1198}
1199
1200return start;
1201}
1202
1203//==============================================================================
1204
1205static u_int32_t GetExtentSize(void * extents, u_int32_t index)
1206{
1207u_int32_t size = 0;
1208
1209HFSExtentDescriptor *hfsExtents = extents;
1210HFSPlusExtentDescriptor *hfsPlusExtents = extents;
1211
1212if (gIsHFSPlus)
1213{
1214size = SWAP_BE32(hfsPlusExtents[index].blockCount);
1215}
1216else
1217{
1218size = SWAP_BE16(hfsExtents[index].blockCount);
1219}
1220
1221return size;
1222}
1223
1224//==============================================================================
1225
1226static long CompareHFSCatalogKeys(void * key, void * testKey)
1227{
1228HFSCatalogKey *searchKey, *trialKey;
1229long result, searchParentID, trialParentID;
1230
1231searchKey = key;
1232trialKey = testKey;
1233
1234searchParentID = SWAP_BE32(searchKey->parentID);
1235trialParentID = SWAP_BE32(trialKey->parentID);
1236
1237// parent dirID is unsigned
1238if (searchParentID > trialParentID)
1239{
1240result = 1;
1241}
1242else if (searchParentID < trialParentID)
1243{
1244result = -1;
1245}
1246else
1247{
1248// parent dirID's are equal, compare names
1249result = FastRelString(searchKey->nodeName, trialKey->nodeName);
1250}
1251
1252return result;
1253}
1254
1255//==============================================================================
1256
1257static long CompareHFSPlusCatalogKeys(void * key, void * testKey)
1258{
1259HFSPlusCatalogKey *searchKey, *trialKey;
1260long result, searchParentID, trialParentID;
1261
1262searchKey = key;
1263trialKey = testKey;
1264
1265searchParentID = SWAP_BE32(searchKey->parentID);
1266trialParentID = SWAP_BE32(trialKey->parentID);
1267
1268// parent dirID is unsigned
1269if (searchParentID > trialParentID)
1270{
1271result = 1;
1272}
1273else if (searchParentID < trialParentID)
1274{
1275result = -1;
1276}
1277else
1278{
1279// parent dirID's are equal, compare names
1280if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0))
1281{
1282result = searchKey->nodeName.length - trialKey->nodeName.length;
1283}
1284else if (gCaseSensitive)
1285{
1286result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0],
1287 SWAP_BE16(searchKey->nodeName.length),
1288 &trialKey->nodeName.unicode[0],
1289 SWAP_BE16(trialKey->nodeName.length));
1290}
1291else
1292{
1293result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],
1294 SWAP_BE16(searchKey->nodeName.length),
1295 &trialKey->nodeName.unicode[0],
1296 SWAP_BE16(trialKey->nodeName.length), OSBigEndian);
1297}
1298}
1299
1300return result;
1301}
1302
1303//==============================================================================
1304
1305static long CompareHFSExtentsKeys(void * key, void * testKey)
1306{
1307HFSExtentKey *searchKey, *trialKey;
1308long result;
1309
1310searchKey = key;
1311trialKey = testKey;
1312
1313// assume searchKey < trialKey
1314result = -1;
1315
1316if (searchKey->fileID == trialKey->fileID)
1317{
1318// FileNum's are equal; compare fork types
1319if (searchKey->forkType == trialKey->forkType)
1320{
1321// Fork types are equal; compare allocation block number
1322if (searchKey->startBlock == trialKey->startBlock)
1323{
1324// Everything is equal
1325result = 0;
1326}
1327else
1328{
1329// Allocation block numbers differ; determine sign
1330if (SWAP_BE16(searchKey->startBlock) > SWAP_BE16(trialKey->startBlock))
1331{
1332result = 1;
1333}
1334}
1335 }
1336else
1337{
1338// Fork types differ; determine sign
1339if (searchKey->forkType > trialKey->forkType)
1340{
1341result = 1;
1342}
1343}
1344}
1345else
1346{
1347// FileNums differ; determine sign
1348if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))
1349{
1350result = 1;
1351}
1352}
1353
1354return result;
1355}
1356
1357
1358//==============================================================================
1359
1360static long CompareHFSPlusExtentsKeys(void * key, void * testKey)
1361{
1362HFSPlusExtentKey*searchKey, *trialKey;
1363
1364longresult;
1365
1366searchKey = key;
1367trialKey = testKey;
1368
1369// assume searchKey < trialKey
1370result = -1;
1371
1372if (searchKey->fileID == trialKey->fileID)
1373{
1374// FileNum's are equal; compare fork types
1375if (searchKey->forkType == trialKey->forkType)
1376{
1377// Fork types are equal; compare allocation block number
1378if (searchKey->startBlock == trialKey->startBlock)
1379{
1380// Everything is equal
1381result = 0;
1382}
1383else
1384{
1385// Allocation block numbers differ; determine sign
1386if (SWAP_BE32(searchKey->startBlock) > SWAP_BE32(trialKey->startBlock))
1387{
1388result = 1;
1389}
1390}
1391}
1392else
1393{
1394// Fork types differ; determine sign
1395if (searchKey->forkType > trialKey->forkType)
1396{
1397result = 1;
1398}
1399}
1400}
1401else
1402{
1403// FileNums differ; determine sign
1404if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))
1405{
1406result = 1;
1407}
1408}
1409
1410 return result;
1411}
1412
1413

Archive Download this file

Revision: 2531