Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2355