Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2182