Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2238