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

Archive Download this file

Revision: 2037