Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/i386/libsaio/hfs.c

Source at commit 214 created 13 years 5 months ago.
By ifabio, update to chameleon trunk 630, and now the pakage folder is the same as blackosx branch, also add Icon "building" into buildpkg script, and add mint theme info into the English localizable.strings.
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
112static void SwapFinderInfo(FndrFileInfo *dst, FndrFileInfo *src)
113{
114 dst->fdType = SWAP_BE32(src->fdType);
115 dst->fdCreator = SWAP_BE32(src->fdCreator);
116 dst->fdFlags = SWAP_BE16(src->fdFlags);
117 // Don't bother with location
118}
119
120void HFSFree(CICell ih)
121{
122 if(gCurrentIH == ih)
123 gCurrentIH = 0;
124 free(ih);
125}
126
127bool HFSProbe (const void *buf)
128{
129const HFSMasterDirectoryBlock *mdb;
130const HFSPlusVolumeHeader *header;
131mdb=(const HFSMasterDirectoryBlock *)(((const char*)buf)+kMDBBaseOffset);
132header=(const HFSPlusVolumeHeader *)(((const char*)buf)+kMDBBaseOffset);
133
134if ( SWAP_BE16(mdb->drSigWord) == kHFSSigWord )
135return true;
136if (SWAP_BE16(header->signature) != kHFSPlusSigWord &&
137 SWAP_BE16(header->signature) != kHFSXSigWord)
138return false;
139return true;
140}
141
142long HFSInitPartition(CICell ih)
143{
144 long extentSize, extentFile, nodeSize;
145 void *extent;
146
147 if (ih == gCurrentIH) {
148#ifdef __i386__
149 CacheInit(ih, gCacheBlockSize);
150#endif
151 return 0;
152 }
153
154#ifdef __i386__
155 if (!gTempStr) gTempStr = (char *)malloc(4096);
156 if (!gLinkTemp) gLinkTemp = (char *)malloc(64);
157 if (!gBTreeHeaderBuffer) gBTreeHeaderBuffer = (char *)malloc(512);
158 if (!gHFSMdbVib) {
159 gHFSMdbVib = (char *)malloc(kBlockSize);
160 gHFSMDB = (HFSMasterDirectoryBlock *)gHFSMdbVib;
161 }
162 if (!gHFSPlusHeader) {
163 gHFSPlusHeader = (char *)malloc(kBlockSize);
164 gHFSPlus = (HFSPlusVolumeHeader *)gHFSPlusHeader;
165 }
166 if (!gTempStr || !gLinkTemp || !gBTreeHeaderBuffer ||
167 !gHFSMdbVib || !gHFSPlusHeader) return -1;
168#endif /* __i386__ */
169
170 gAllocationOffset = 0;
171 gIsHFSPlus = 0;
172 gCaseSensitive = 0;
173 gBTHeaders[0] = 0;
174 gBTHeaders[1] = 0;
175
176 // Look for the HFS MDB
177 Seek(ih, kMDBBaseOffset);
178 Read(ih, (long)gHFSMdbVib, kBlockSize);
179
180 if ( SWAP_BE16(gHFSMDB->drSigWord) == kHFSSigWord ) {
181 gAllocationOffset = SWAP_BE16(gHFSMDB->drAlBlSt) * kBlockSize;
182
183 // See if it is HFSPlus
184 if (SWAP_BE16(gHFSMDB->drEmbedSigWord) != kHFSPlusSigWord) {
185 // Normal HFS;
186 gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSMDB->drAlBlkSiz);
187 CacheInit(ih, gCacheBlockSize);
188 gCurrentIH = ih;
189
190 // grab the 64 bit volume ID
191 bcopy(&gHFSMDB->drFndrInfo[6], &gVolID, 8);
192
193 // Get the Catalog BTree node size.
194 extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;
195 extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);
196 extentFile = kHFSCatalogFileID;
197 ReadExtent(extent, extentSize, extentFile, 0, 256,
198 gBTreeHeaderBuffer + kBTreeCatalog * 256, 0);
199
200 nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 +
201 sizeof(BTNodeDescriptor)))->nodeSize);
202
203 // If the BTree node size is larger than the block size, reset the cache.
204 if (nodeSize > gBlockSize) {
205 gCacheBlockSize = nodeSize;
206 CacheInit(ih, gCacheBlockSize);
207 }
208
209 return 0;
210 }
211
212 // Calculate the offset to the embeded HFSPlus volume.
213 gAllocationOffset += (long long)SWAP_BE16(gHFSMDB->drEmbedExtent.startBlock) *
214 SWAP_BE32(gHFSMDB->drAlBlkSiz);
215 }
216
217 // Look for the HFSPlus Header
218 Seek(ih, gAllocationOffset + kMDBBaseOffset);
219 Read(ih, (long)gHFSPlusHeader, kBlockSize);
220
221 // Not a HFS+ or HFSX volume.
222 if (SWAP_BE16(gHFSPlus->signature) != kHFSPlusSigWord &&
223 SWAP_BE16(gHFSPlus->signature) != kHFSXSigWord) {
224verbose("HFS signature was not present.\n");
225 gCurrentIH = 0;
226return -1;
227 }
228
229 gIsHFSPlus = 1;
230 gCacheBlockSize = gBlockSize = SWAP_BE32(gHFSPlus->blockSize);
231 CacheInit(ih, gCacheBlockSize);
232 gCurrentIH = ih;
233
234ih->modTime = SWAP_BE32(gHFSPlus->modifyDate) - 2082844800;
235
236 // grab the 64 bit volume ID
237 bcopy(&gHFSPlus->finderInfo[24], &gVolID, 8);
238
239 // Get the Catalog BTree node size.
240 extent = &gHFSPlus->catalogFile.extents;
241 extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);
242 extentFile = kHFSCatalogFileID;
243
244 ReadExtent(extent, extentSize, extentFile, 0, 256,
245 gBTreeHeaderBuffer + kBTreeCatalog * 256, 0);
246
247 nodeSize = SWAP_BE16(((BTHeaderRec *)(gBTreeHeaderBuffer + kBTreeCatalog * 256 +
248 sizeof(BTNodeDescriptor)))->nodeSize);
249
250 // If the BTree node size is larger than the block size, reset the cache.
251 if (nodeSize > gBlockSize) {
252 gCacheBlockSize = nodeSize;
253 CacheInit(ih, gCacheBlockSize);
254 }
255
256 return 0;
257}
258
259long HFSLoadFile(CICell ih, char * filePath)
260{
261 return HFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);
262}
263
264long HFSReadFile(CICell ih, char * filePath, void *base, uint64_t offset, uint64_t length)
265{
266 char entry[512];
267 char devStr[12];
268 long dirID, result, flags;
269
270 if (HFSInitPartition(ih) == -1) return -1;
271
272 dirID = kHFSRootFolderID;
273 // Skip a lead '\'. Start in the system folder if there are two.
274 if (filePath[0] == '/') {
275 if (filePath[1] == '/') {
276 if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);
277 else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);
278 if (dirID == 0) {
279return -1;
280 }
281 filePath++;
282 }
283 filePath++;
284 }
285
286 result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);
287 if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
288return -1;
289 }
290
291#if UNUSED
292 // Not yet for Intel. System.config/Default.table will fail this check.
293 // Check file owner and permissions.
294 if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1;
295#endif
296
297 result = ReadFile(entry, &length, base, offset);
298 if (result == -1) {
299return -1;
300 }
301
302 getDeviceDescription(ih, devStr);
303 verbose("Read HFS%s file: [%s/%s] %d bytes.\n",
304 (gIsHFSPlus ? "+" : ""), devStr, filePath, (uint32_t)length);
305
306 return length;
307}
308
309long HFSGetDirEntry(CICell ih, char * dirPath, long long * dirIndex, char ** name,
310 long * flags, long * time,
311 FinderInfo * finderInfo, long * infoValid)
312{
313 char entry[512];
314 long dirID, dirFlags;
315
316 if (HFSInitPartition(ih) == -1) return -1;
317
318 if (*dirIndex == -1) return -1;
319
320 dirID = kHFSRootFolderID;
321 // Skip a lead '\'. Start in the system folder if there are two.
322 if (dirPath[0] == '/') {
323 if (dirPath[1] == '/') {
324 if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);
325 else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);
326 if (dirID == 0) return -1;
327 dirPath++;
328 }
329 dirPath++;
330 }
331
332 if (*dirIndex == 0) {
333 ResolvePathToCatalogEntry(dirPath, &dirFlags, entry, dirID, dirIndex);
334 if (*dirIndex == 0) *dirIndex = -1;
335 if ((dirFlags & kFileTypeMask) != kFileTypeUnknown) return -1;
336 }
337
338 GetCatalogEntry(dirIndex, name, flags, time, finderInfo, infoValid);
339 if (*dirIndex == 0) *dirIndex = -1;
340 if ((*flags & kFileTypeMask) == kFileTypeUnknown) return -1;
341
342 return 0;
343}
344
345void
346HFSGetDescription(CICell ih, char *str, long strMaxLen)
347{
348
349 UInt16 nodeSize;
350 UInt32 firstLeafNode;
351 long long dirIndex;
352 char *name;
353 long flags, time;
354
355 if (HFSInitPartition(ih) == -1) { return; }
356
357 /* Fill some crucial data structures by side effect. */
358 dirIndex = 0;
359 HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
360
361 /* Now we can loook up the volume name node. */
362 nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
363 firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
364
365 dirIndex = (long long) firstLeafNode * nodeSize;
366
367 GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
368
369 strncpy(str, name, strMaxLen);
370 str[strMaxLen] = '\0';
371}
372
373
374long
375HFSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
376{
377 char entry[512];
378 long dirID, result, flags;
379 void *extents;
380 HFSCatalogFile *hfsFile = (void *)entry;
381 HFSPlusCatalogFile *hfsPlusFile = (void *)entry;
382
383 if (HFSInitPartition(ih) == -1) return -1;
384
385 dirID = kHFSRootFolderID;
386 // Skip a lead '\'. Start in the system folder if there are two.
387 if (filePath[0] == '/') {
388 if (filePath[1] == '/') {
389 if (gIsHFSPlus) dirID = SWAP_BE32(((long *)gHFSPlus->finderInfo)[5]);
390 else dirID = SWAP_BE32(gHFSMDB->drFndrInfo[5]);
391 if (dirID == 0) {
392return -1;
393 }
394 filePath++;
395 }
396 filePath++;
397 }
398
399 result = ResolvePathToCatalogEntry(filePath, &flags, entry, dirID, 0);
400 if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
401 printf("HFS: Resolve path %s failed\n", filePath);
402return -1;
403 }
404
405 if (gIsHFSPlus) {
406 extents = &hfsPlusFile->dataFork.extents;
407 } else {
408 extents = &hfsFile->dataExtents;
409 }
410
411#if DEBUG
412 printf("extent start 0x%x\n", (unsigned long)GetExtentStart(extents, 0));
413 printf("block size 0x%x\n", (unsigned long)gBlockSize);
414 printf("Allocation offset 0x%x\n", (unsigned long)gAllocationOffset);
415#endif
416 *firstBlock = ((unsigned long long)GetExtentStart(extents, 0) * (unsigned long long) gBlockSize + gAllocationOffset) / 512ULL;
417 return 0;
418}
419
420long HFSGetUUID(CICell ih, char *uuidStr)
421{
422 if (HFSInitPartition(ih) == -1) return -1;
423 if (gVolID == 0LL) return -1;
424
425 return CreateUUIDString((uint8_t*)(&gVolID), sizeof(gVolID), uuidStr);
426}
427
428// Private Functions
429
430static long ReadFile(void * file, uint64_t * length, void * base, uint64_t offset)
431{
432 void *extents;
433 long fileID;
434 uint64_t fileLength;
435 HFSCatalogFile *hfsFile = file;
436 HFSPlusCatalogFile *hfsPlusFile = file;
437
438 if (gIsHFSPlus) {
439 fileID = SWAP_BE32(hfsPlusFile->fileID);
440 fileLength = (uint64_t)SWAP_BE64(hfsPlusFile->dataFork.logicalSize);
441 extents = &hfsPlusFile->dataFork.extents;
442 } else {
443 fileID = SWAP_BE32(hfsFile->fileID);
444 fileLength = SWAP_BE32(hfsFile->dataLogicalSize);
445 extents = &hfsFile->dataExtents;
446 }
447
448 if (offset > fileLength) {
449 printf("Offset is too large.\n");
450 return -1;
451 }
452
453 if ((*length == 0) || ((offset + *length) > fileLength)) {
454 *length = fileLength - offset;
455 }
456
457/* if (*length > kLoadSize) {
458 printf("File is too large.\n");
459 return -1;
460 }*/
461
462 *length = ReadExtent((char *)extents, fileLength, fileID,
463 offset, *length, (char *)base, 0);
464
465 return 0;
466}
467
468static long GetCatalogEntryInfo(void * entry, long * flags, long * time,
469 FinderInfo * finderInfo, long * infoValid)
470{
471 long tmpTime = 0;
472 long valid = 0;
473
474 // Get information about the file.
475
476 switch ( SWAP_BE16(*(short *)entry) )
477 {
478 case kHFSFolderRecord :
479 *flags = kFileTypeDirectory;
480 tmpTime = SWAP_BE32(((HFSCatalogFolder *)entry)->modifyDate);
481 break;
482
483 case kHFSPlusFolderRecord :
484 *flags = kFileTypeDirectory |
485 (SWAP_BE16(((HFSPlusCatalogFolder *)entry)->bsdInfo.fileMode) & kPermMask);
486 if (SWAP_BE32(((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID) != 0)
487 *flags |= kOwnerNotRoot;
488 tmpTime = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->contentModDate);
489 break;
490
491 case kHFSFileRecord :
492 *flags = kFileTypeFlat;
493 tmpTime = SWAP_BE32(((HFSCatalogFile *)entry)->modifyDate);
494 if (finderInfo) {
495 SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSCatalogFile *)entry)->userInfo);
496 valid = 1;
497 }
498 break;
499
500 case kHFSPlusFileRecord :
501 *flags = kFileTypeFlat |
502 (SWAP_BE16(((HFSPlusCatalogFile *)entry)->bsdInfo.fileMode) & kPermMask);
503 if (SWAP_BE32(((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID) != 0)
504 *flags |= kOwnerNotRoot;
505 tmpTime = SWAP_BE32(((HFSPlusCatalogFile *)entry)->contentModDate);
506 if (finderInfo) {
507 SwapFinderInfo((FndrFileInfo *)finderInfo, &((HFSPlusCatalogFile *)entry)->userInfo);
508 valid = 1;
509 }
510 break;
511
512 case kHFSFileThreadRecord :
513 case kHFSPlusFileThreadRecord :
514 case kHFSFolderThreadRecord :
515 case kHFSPlusFolderThreadRecord :
516 *flags = kFileTypeUnknown;
517 tmpTime = 0;
518 break;
519 }
520
521 if (time != 0) {
522 // Convert base time from 1904 to 1970.
523 *time = tmpTime - 2082844800;
524 }
525 if (infoValid) *infoValid = valid;
526
527 return 0;
528}
529
530static long ResolvePathToCatalogEntry(char * filePath, long * flags,
531 void * entry, long dirID, long long * dirIndex)
532{
533 char *restPath;
534 long result, cnt, subFolderID = 0;
535 long long tmpDirIndex;
536 HFSPlusCatalogFile *hfsPlusFile;
537
538 // Copy the file name to gTempStr
539 cnt = 0;
540 while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++;
541 strlcpy(gTempStr, filePath, cnt+1);
542
543 // Move restPath to the right place.
544 if (filePath[cnt] != '\0') cnt++;
545 restPath = filePath + cnt;
546
547 // gTempStr is a name in the current Dir.
548 // restPath is the rest of the path if any.
549
550 result = ReadCatalogEntry(gTempStr, dirID, entry, dirIndex);
551 if (result == -1) {
552return -1;
553 }
554
555 GetCatalogEntryInfo(entry, flags, 0, 0, 0);
556
557 if ((*flags & kFileTypeMask) == kFileTypeDirectory) {
558 if (gIsHFSPlus)
559 subFolderID = SWAP_BE32(((HFSPlusCatalogFolder *)entry)->folderID);
560 else
561 subFolderID = SWAP_BE32(((HFSCatalogFolder *)entry)->folderID);
562 }
563
564 if ((*flags & kFileTypeMask) == kFileTypeDirectory)
565 result = ResolvePathToCatalogEntry(restPath, flags, entry,
566 subFolderID, dirIndex);
567
568 if (gIsHFSPlus && ((*flags & kFileTypeMask) == kFileTypeFlat)) {
569 hfsPlusFile = (HFSPlusCatalogFile *)entry;
570 if ((SWAP_BE32(hfsPlusFile->userInfo.fdType) == kHardLinkFileType) &&
571 (SWAP_BE32(hfsPlusFile->userInfo.fdCreator) == kHFSPlusCreator)) {
572 sprintf(gLinkTemp, "%s/%s%ld", HFSPLUSMETADATAFOLDER,
573 HFS_INODE_PREFIX, SWAP_BE32(hfsPlusFile->bsdInfo.special.iNodeNum));
574 result = ResolvePathToCatalogEntry(gLinkTemp, flags, entry,
575 kHFSRootFolderID, &tmpDirIndex);
576 }
577 }
578
579 return result;
580}
581
582static long GetCatalogEntry(long long * dirIndex, char ** name,
583 long * flags, long * time,
584 FinderInfo * finderInfo, long * infoValid)
585{
586 long extentSize, nodeSize, curNode, index;
587 void *extent;
588 char *nodeBuf, *testKey, *entry;
589 BTNodeDescriptor *node;
590
591 if (gIsHFSPlus) {
592 extent = &gHFSPlus->catalogFile.extents;
593 extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);
594 } else {
595 extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;
596 extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);
597 }
598
599 nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
600 nodeBuf = (char *)malloc(nodeSize);
601 node = (BTNodeDescriptor *)nodeBuf;
602
603 index = (long) (*dirIndex % nodeSize);
604 curNode = (long) (*dirIndex / nodeSize);
605
606 // Read the BTree node and get the record for index.
607 ReadExtent(extent, extentSize, kHFSCatalogFileID,
608 (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
609 GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);
610
611 GetCatalogEntryInfo(entry, flags, time, finderInfo, infoValid);
612
613 // Get the file name.
614 if (gIsHFSPlus) {
615 utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,
616 SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),
617 (u_int8_t *)gTempStr, 256, OSBigEndian);
618 } else {
619 strncpy(gTempStr,
620 (const char *)&((HFSCatalogKey *)testKey)->nodeName[1],
621 ((HFSCatalogKey *)testKey)->nodeName[0]);
622 gTempStr[((HFSCatalogKey *)testKey)->nodeName[0]] = '\0';
623 }
624 *name = gTempStr;
625
626 // Update dirIndex.
627 index++;
628 if (index == SWAP_BE16(node->numRecords)) {
629 index = 0;
630 curNode = SWAP_BE32(node->fLink);
631 }
632 *dirIndex = (long long) curNode * nodeSize + index;
633
634 free(nodeBuf);
635
636 return 0;
637}
638
639static long ReadCatalogEntry(char * fileName, long dirID,
640 void * entry, long long * dirIndex)
641{
642 long length;
643 char key[sizeof(HFSPlusCatalogKey)];
644 HFSCatalogKey *hfsKey = (HFSCatalogKey *)key;
645 HFSPlusCatalogKey *hfsPlusKey = (HFSPlusCatalogKey *)key;
646
647 // Make the catalog key.
648 if ( gIsHFSPlus )
649 {
650 hfsPlusKey->parentID = SWAP_BE32(dirID);
651 length = strlen(fileName);
652 if (length > 255) length = 255;
653 utf_decodestr((u_int8_t *)fileName, hfsPlusKey->nodeName.unicode,
654 &(hfsPlusKey->nodeName.length), 512, OSBigEndian);
655 } else {
656 hfsKey->parentID = SWAP_BE32(dirID);
657 length = strlen(fileName);
658 if (length > 31) length = 31;
659 hfsKey->nodeName[0] = length;
660 strncpy((char *)(hfsKey->nodeName + 1), fileName, length);
661 }
662
663 return ReadBTreeEntry(kBTreeCatalog, &key, entry, dirIndex);
664}
665
666static long ReadExtentsEntry(long fileID, long startBlock, void * entry)
667{
668 char key[sizeof(HFSPlusExtentKey)];
669 HFSExtentKey *hfsKey = (HFSExtentKey *)key;
670 HFSPlusExtentKey *hfsPlusKey = (HFSPlusExtentKey *)key;
671
672 // Make the extents key.
673 if (gIsHFSPlus) {
674 hfsPlusKey->forkType = 0;
675 hfsPlusKey->fileID = SWAP_BE32(fileID);
676 hfsPlusKey->startBlock = SWAP_BE32(startBlock);
677 } else {
678 hfsKey->forkType = 0;
679 hfsKey->fileID = SWAP_BE32(fileID);
680 hfsKey->startBlock = SWAP_BE16(startBlock);
681 }
682
683 return ReadBTreeEntry(kBTreeExtents, &key, entry, 0);
684}
685
686static long ReadBTreeEntry(long btree, void * key, char * entry, long long * dirIndex)
687{
688 long extentSize;
689 void *extent;
690 short extentFile;
691 char *nodeBuf;
692 BTNodeDescriptor *node;
693 long nodeSize, result = 0, entrySize = 0;
694 long curNode, index = 0, lowerBound, upperBound;
695 char *testKey, *recordData;
696
697 // Figure out which tree is being looked at.
698 if (btree == kBTreeCatalog) {
699 if (gIsHFSPlus) {
700 extent = &gHFSPlus->catalogFile.extents;
701 extentSize = SWAP_BE64(gHFSPlus->catalogFile.logicalSize);
702 } else {
703 extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec;
704 extentSize = SWAP_BE32(gHFSMDB->drCTFlSize);
705 }
706 extentFile = kHFSCatalogFileID;
707 } else {
708 if (gIsHFSPlus) {
709 extent = &gHFSPlus->extentsFile.extents;
710 extentSize = SWAP_BE64(gHFSPlus->extentsFile.logicalSize);
711 } else {
712 extent = (HFSExtentDescriptor *)&gHFSMDB->drXTExtRec;
713 extentSize = SWAP_BE32(gHFSMDB->drXTFlSize);
714 }
715 extentFile = kHFSExtentsFileID;
716 }
717
718 // Read the BTree Header if needed.
719 if (gBTHeaders[btree] == 0) {
720 ReadExtent(extent, extentSize, extentFile, 0, 256,
721 gBTreeHeaderBuffer + btree * 256, 0);
722 gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 +
723 sizeof(BTNodeDescriptor));
724 if ((gIsHFSPlus && btree == kBTreeCatalog) &&
725 (gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare)) {
726 gCaseSensitive = 1;
727 }
728 }
729
730 curNode = SWAP_BE32(gBTHeaders[btree]->rootNode);
731 nodeSize = SWAP_BE16(gBTHeaders[btree]->nodeSize);
732 nodeBuf = (char *)malloc(nodeSize);
733 node = (BTNodeDescriptor *)nodeBuf;
734
735 while (1) {
736 // Read the current node.
737 ReadExtent(extent, extentSize, extentFile,
738 (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
739
740 // Find the matching key.
741 lowerBound = 0;
742 upperBound = SWAP_BE16(node->numRecords) - 1;
743 while (lowerBound <= upperBound) {
744 index = (lowerBound + upperBound) / 2;
745
746 GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);
747
748 if (gIsHFSPlus) {
749 if (btree == kBTreeCatalog) {
750 result = CompareHFSPlusCatalogKeys(key, testKey);
751 } else {
752 result = CompareHFSPlusExtentsKeys(key, testKey);
753 }
754 } else {
755 if (btree == kBTreeCatalog) {
756 result = CompareHFSCatalogKeys(key, testKey);
757 } else {
758 result = CompareHFSExtentsKeys(key, testKey);
759 }
760 }
761
762 if (result < 0) upperBound = index - 1; // search < trial
763 else if (result > 0) lowerBound = index + 1; // search > trial
764 else break; // search = trial
765 }
766
767 if (result < 0) {
768 index = upperBound;
769 GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &recordData);
770 }
771
772 // Found the closest key... Recurse on it if this is an index node.
773 if (node->kind == kBTIndexNode) {
774 curNode = SWAP_BE32( *((long *)recordData) );
775 } else break;
776 }
777
778 // Return error if the file was not found.
779 if (result != 0) { free(nodeBuf); return -1; }
780
781 if (btree == kBTreeCatalog) {
782 switch (SWAP_BE16(*(short *)recordData)) {
783 case kHFSFolderRecord : entrySize = 70; break;
784 case kHFSFileRecord : entrySize = 102; break;
785 case kHFSFolderThreadRecord : entrySize = 46; break;
786 case kHFSFileThreadRecord : entrySize = 46; break;
787 case kHFSPlusFolderRecord : entrySize = 88; break;
788 case kHFSPlusFileRecord : entrySize = 248; break;
789 case kHFSPlusFolderThreadRecord : entrySize = 264; break;
790 case kHFSPlusFileThreadRecord : entrySize = 264; break;
791 }
792 } else {
793 if (gIsHFSPlus) entrySize = sizeof(HFSPlusExtentRecord);
794 else entrySize = sizeof(HFSExtentRecord);
795 }
796
797 bcopy(recordData, entry, entrySize);
798
799 // Update dirIndex.
800 if (dirIndex != 0) {
801 index++;
802 if (index == SWAP_BE16(node->numRecords)) {
803 index = 0;
804 curNode = SWAP_BE32(node->fLink);
805 }
806 *dirIndex = (long long) curNode * nodeSize + index;
807 }
808
809 free(nodeBuf);
810
811 return 0;
812}
813
814static void GetBTreeRecord(long index, char * nodeBuffer, long nodeSize,
815 char ** key, char ** data)
816{
817 long keySize;
818 long recordOffset;
819
820 recordOffset = SWAP_BE16(*((short *)(nodeBuffer + (nodeSize - 2 * index - 2))));
821 *key = nodeBuffer + recordOffset;
822 if (gIsHFSPlus) {
823 keySize = SWAP_BE16(*(short *)*key);
824 *data = *key + 2 + keySize;
825 } else {
826 keySize = **key;
827 *data = *key + 2 + keySize - (keySize & 1);
828 }
829}
830
831static long ReadExtent(char * extent, uint64_t extentSize,
832 long extentFile, uint64_t offset, uint64_t size,
833 void * buffer, long cache)
834{
835 uint64_t lastOffset;
836long long blockNumber, countedBlocks = 0;
837 long long nextExtent = 0, sizeRead = 0, readSize;
838 long long nextExtentBlock, currentExtentBlock = 0;
839 long long readOffset;
840 long long extentDensity, sizeofExtent, currentExtentSize;
841 char *currentExtent, *extentBuffer = 0, *bufferPos = buffer;
842
843 if (offset >= extentSize) return 0;
844
845 if (gIsHFSPlus) {
846 extentDensity = kHFSPlusExtentDensity;
847 sizeofExtent = sizeof(HFSPlusExtentDescriptor);
848 } else {
849 extentDensity = kHFSExtentDensity;
850 sizeofExtent = sizeof(HFSExtentDescriptor);
851 }
852
853 lastOffset = offset + size;
854 while (offset < lastOffset) {
855 blockNumber = offset / gBlockSize;
856
857 // Find the extent for the offset.
858 for (; ; nextExtent++) {
859 if (nextExtent < extentDensity) {
860 if ((countedBlocks+GetExtentSize(extent, nextExtent)-1)<blockNumber) {
861 countedBlocks += GetExtentSize(extent, nextExtent);
862 continue;
863 }
864
865 currentExtent = extent + nextExtent * sizeofExtent;
866 break;
867 }
868
869 if (extentBuffer == 0) {
870 extentBuffer = malloc(sizeofExtent * extentDensity);
871 if (extentBuffer == 0) return -1;
872 }
873
874 nextExtentBlock = nextExtent / extentDensity;
875 if (currentExtentBlock != nextExtentBlock) {
876 ReadExtentsEntry(extentFile, countedBlocks, extentBuffer);
877 currentExtentBlock = nextExtentBlock;
878 }
879
880 currentExtentSize = GetExtentSize(extentBuffer, nextExtent % extentDensity);
881
882 if ((countedBlocks + currentExtentSize - 1) >= blockNumber) {
883 currentExtent = extentBuffer + sizeofExtent * (nextExtent % extentDensity);
884 break;
885 }
886
887 countedBlocks += currentExtentSize;
888 }
889
890 readOffset = ((blockNumber - countedBlocks) * gBlockSize) +
891 (offset % gBlockSize);
892
893// MacWen: fix overflow in multiplication by forcing 64bit multiplication
894 readSize = (long long)GetExtentSize(currentExtent, 0) * gBlockSize - readOffset;
895 if (readSize > (size - sizeRead)) readSize = size - sizeRead;
896
897 readOffset += (long long)GetExtentStart(currentExtent, 0) * gBlockSize;
898
899 CacheRead(gCurrentIH, bufferPos, gAllocationOffset + readOffset,
900 readSize, cache);
901
902 sizeRead += readSize;
903 offset += readSize;
904 bufferPos += readSize;
905 }
906
907 if (extentBuffer) free(extentBuffer);
908
909 return sizeRead;
910}
911
912static long GetExtentStart(void * extents, long index)
913{
914 long start;
915 HFSExtentDescriptor *hfsExtents = extents;
916 HFSPlusExtentDescriptor *hfsPlusExtents = extents;
917
918 if (gIsHFSPlus) start = SWAP_BE32(hfsPlusExtents[index].startBlock);
919 else start = SWAP_BE16(hfsExtents[index].startBlock);
920
921 return start;
922}
923
924static long GetExtentSize(void * extents, long index)
925{
926 long size;
927 HFSExtentDescriptor *hfsExtents = extents;
928 HFSPlusExtentDescriptor *hfsPlusExtents = extents;
929
930 if (gIsHFSPlus) size = SWAP_BE32(hfsPlusExtents[index].blockCount);
931 else size = SWAP_BE16(hfsExtents[index].blockCount);
932
933 return size;
934}
935
936static long CompareHFSCatalogKeys(void * key, void * testKey)
937{
938 HFSCatalogKey *searchKey, *trialKey;
939 long result, searchParentID, trialParentID;
940
941 searchKey = key;
942 trialKey = testKey;
943
944 searchParentID = SWAP_BE32(searchKey->parentID);
945 trialParentID = SWAP_BE32(trialKey->parentID);
946
947 // parent dirID is unsigned
948 if (searchParentID > trialParentID) result = 1;
949 else if (searchParentID < trialParentID) result = -1;
950 else {
951 // parent dirID's are equal, compare names
952 result = FastRelString(searchKey->nodeName, trialKey->nodeName);
953 }
954
955 return result;
956}
957
958static long CompareHFSPlusCatalogKeys(void * key, void * testKey)
959{
960 HFSPlusCatalogKey *searchKey, *trialKey;
961 long result, searchParentID, trialParentID;
962
963 searchKey = key;
964 trialKey = testKey;
965
966 searchParentID = SWAP_BE32(searchKey->parentID);
967 trialParentID = SWAP_BE32(trialKey->parentID);
968
969 // parent dirID is unsigned
970 if (searchParentID > trialParentID) result = 1;
971 else if (searchParentID < trialParentID) result = -1;
972 else {
973 // parent dirID's are equal, compare names
974 if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0))
975 result = searchKey->nodeName.length - trialKey->nodeName.length;
976 else
977 if (gCaseSensitive) {
978 result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0],
979 SWAP_BE16(searchKey->nodeName.length),
980 &trialKey->nodeName.unicode[0],
981 SWAP_BE16(trialKey->nodeName.length));
982 } else {
983 result = FastUnicodeCompare(&searchKey->nodeName.unicode[0],
984 SWAP_BE16(searchKey->nodeName.length),
985 &trialKey->nodeName.unicode[0],
986 SWAP_BE16(trialKey->nodeName.length), OSBigEndian);
987 }
988 }
989
990 return result;
991}
992
993static long CompareHFSExtentsKeys(void * key, void * testKey)
994{
995 HFSExtentKey *searchKey, *trialKey;
996 long result;
997
998 searchKey = key;
999 trialKey = testKey;
1000
1001 // assume searchKey < trialKey
1002 result = -1;
1003
1004 if (searchKey->fileID == trialKey->fileID) {
1005 // FileNum's are equal; compare fork types
1006 if (searchKey->forkType == trialKey->forkType) {
1007 // Fork types are equal; compare allocation block number
1008 if (searchKey->startBlock == trialKey->startBlock) {
1009 // Everything is equal
1010 result = 0;
1011 } else {
1012 // Allocation block numbers differ; determine sign
1013 if (SWAP_BE16(searchKey->startBlock) > SWAP_BE16(trialKey->startBlock))
1014 result = 1;
1015 }
1016 } else {
1017 // Fork types differ; determine sign
1018 if (searchKey->forkType > trialKey->forkType) result = 1;
1019 }
1020 } else {
1021 // FileNums differ; determine sign
1022 if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))
1023 result = 1;
1024 }
1025
1026 return result;
1027}
1028
1029static long CompareHFSPlusExtentsKeys(void * key, void * testKey)
1030{
1031 HFSPlusExtentKey *searchKey, *trialKey;
1032 long result;
1033
1034 searchKey = key;
1035 trialKey = testKey;
1036
1037 // assume searchKey < trialKey
1038 result = -1;
1039
1040 if (searchKey->fileID == trialKey->fileID) {
1041 // FileNum's are equal; compare fork types
1042 if (searchKey->forkType == trialKey->forkType) {
1043 // Fork types are equal; compare allocation block number
1044 if (searchKey->startBlock == trialKey->startBlock) {
1045 // Everything is equal
1046 result = 0;
1047 } else {
1048 // Allocation block numbers differ; determine sign
1049 if (SWAP_BE32(searchKey->startBlock) > SWAP_BE32(trialKey->startBlock))
1050 result = 1;
1051 }
1052 } else {
1053 // Fork types differ; determine sign
1054 if (searchKey->forkType > trialKey->forkType) result = 1;
1055 }
1056 } else {
1057 // FileNums differ; determine sign
1058 if (SWAP_BE32(searchKey->fileID) > SWAP_BE32(trialKey->fileID))
1059 result = 1;
1060 }
1061
1062 return result;
1063}
1064
1065

Archive Download this file

Revision: 214