Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Trunk/i386/libsaio/hfs.c

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

Archive Download this file

Revision: 2045