X-Git-Url: https://git.saurik.com/apple/bootx.git/blobdiff_plain/366defd12be2eb202aa24e420675ae85aae1d5d0..HEAD:/bootx.tproj/fs.subproj/hfs.c diff --git a/bootx.tproj/fs.subproj/hfs.c b/bootx.tproj/fs.subproj/hfs.c index ea65af4..198b4ef 100644 --- a/bootx.tproj/fs.subproj/hfs.c +++ b/bootx.tproj/fs.subproj/hfs.c @@ -1,28 +1,35 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ + /* * hfs.c - File System Module for HFS and HFS+. * - * Copyright (c) 1999-2002 Apple Computer, Inc. + * Copyright (c) 1999-2004 Apple Computer, Inc. * * DRI: Josh de Cesare */ @@ -40,7 +47,8 @@ static CICell gCurrentIH; static long long gAllocationOffset; static long gIsHFSPlus; -static long gBlockSize; +static long gCaseSensitive; +static unsigned long gBlockSize; static char gBTreeHeaderBuffer[512]; static BTHeaderRec *gBTHeaders[2]; static char gHFSMdbVib[kBlockSize]; @@ -48,28 +56,30 @@ static HFSMasterDirectoryBlock *gHFSMDB =(HFSMasterDirectoryBlock*)gHFSMdbVib; static char gHFSPlusHeader[kBlockSize]; static HFSPlusVolumeHeader *gHFSPlus =(HFSPlusVolumeHeader*)gHFSPlusHeader; static char gLinkTemp[64]; +static long long gVolID; -static long ReadFile(void *file, long *length); +static long ReadFile(void *file, long *length, void *base, long offset); static long GetCatalogEntryInfo(void *entry, long *flags, long *time); -static long ResolvePathToCatalogEntry(char *filePath, long *flags, - void *entry, long dirID, long *dirIndex); +static long ResolvePathToCatalogEntry(char *filePath, long *flags, void *entry, + unsigned long dirID, unsigned long *dirIndex); -static long GetCatalogEntry(long *dirIndex, char **name, +static long GetCatalogEntry(unsigned long *dirIndex, char **name, long *flags, long *time); -static long ReadCatalogEntry(char *fileName, long dirID, void *entry, - long *dirIndex); -static long ReadExtentsEntry(long fileID, long startBlock, void *entry); +static long ReadCatalogEntry(char *fileName, unsigned long dirID, void *entry, + unsigned long *dirIndex); +static long ReadExtentsEntry(unsigned long fileID, unsigned long startBlock, void *entry); -static long ReadBTreeEntry(long btree, void *key, char *entry, long *dirIndex); +static long ReadBTreeEntry(long btree, void *key, char *entry, + unsigned long *dirIndex); static void GetBTreeRecord(long index, char *nodeBuffer, long nodeSize, char **key, char **data); -static long ReadExtent(char *extent, long extentSize, long extentFile, - long offset, long size, void *buffer, long cache); +static long ReadExtent(void *extent, u_int64_t extentSize, unsigned long extentFile, + u_int64_t offset, long size, void *buffer, long cache); -static long GetExtentStart(void *extents, long index); -static long GetExtentSize(void *extents, long index); +static unsigned long GetExtentStart(void *extents, long index); +static unsigned long GetExtentSize(void *extents, long index); static long CompareHFSCatalogKeys(void *key, void *testKey); static long CompareHFSPlusCatalogKeys(void *key, void *testKey); @@ -79,6 +89,8 @@ static long CompareHFSPlusExtentsKeys(void *key, void *testKey); extern long FastRelString(char *str1, char *str2); extern long FastUnicodeCompare(u_int16_t *uniStr1, u_int32_t len1, u_int16_t *uniStr2, u_int32_t len2); +extern long BinaryUnicodeCompare(u_int16_t *uniStr1, u_int32_t len1, + u_int16_t *uniStr2, u_int32_t len2); extern void utf_encodestr(const u_int16_t *ucsp, int ucslen, u_int8_t *utf8p, u_int32_t bufsize); extern void utf_decodestr(const u_int8_t *utf8p, u_int16_t *ucsp, @@ -87,7 +99,9 @@ extern void utf_decodestr(const u_int8_t *utf8p, u_int16_t *ucsp, long HFSInitPartition(CICell ih) { - long extentSize, extentFile, nodeSize; + unsigned long extentFile; + long nodeSize; + u_int64_t extentSize; void *extent; if (ih == gCurrentIH) return 0; @@ -96,11 +110,12 @@ long HFSInitPartition(CICell ih) gAllocationOffset = 0; gIsHFSPlus = 0; + gCaseSensitive = 0; gBTHeaders[0] = 0; gBTHeaders[1] = 0; // Look for the HFS MDB - Seek(ih, kMDBBaseOffset); + Seek(ih, (long long)kMDBBaseOffset); Read(ih, (long)gHFSMdbVib, kBlockSize); if (gHFSMDB->drSigWord == kHFSSigWord) { @@ -112,6 +127,9 @@ long HFSInitPartition(CICell ih) gBlockSize = gHFSMDB->drAlBlkSiz; CacheInit(ih, gBlockSize); gCurrentIH = ih; + + // grab the 64 bit volume ID + bcopy(&gHFSMDB->drFndrInfo[6], &gVolID, 8); // Get the Catalog BTree node size. extent = (HFSExtentDescriptor *)&gHFSMDB->drCTExtRec; @@ -135,14 +153,20 @@ long HFSInitPartition(CICell ih) Seek(ih, gAllocationOffset + kMDBBaseOffset); Read(ih, (long)gHFSPlusHeader, kBlockSize); +//printf("checking signatures...\n"); // Not a HFS[+] volume. - if (gHFSPlus->signature != kHFSPlusSigWord) return -1; - + if ((gHFSPlus->signature != kHFSPlusSigWord) && + (gHFSPlus->signature != kHFSXSigWord)) return -1; +//printf("continuing with HFS\n"); + gIsHFSPlus = 1; gBlockSize = gHFSPlus->blockSize; CacheInit(ih, gBlockSize); gCurrentIH = ih; + // grab the 64 bit volume ID + bcopy(&gHFSPlus->finderInfo[24], &gVolID, 8); + // Get the Catalog BTree node size. extent = &gHFSPlus->catalogFile.extents; extentSize = gHFSPlus->catalogFile.logicalSize; @@ -158,13 +182,21 @@ long HFSInitPartition(CICell ih) } long HFSLoadFile(CICell ih, char *filePath) +{ + return HFSReadFile(ih, filePath, (void *)kLoadAddr, 0, 0); +} + +extern long HFSReadFile(CICell ih, char *filePath, void *base, + unsigned long offset, unsigned long length) { char entry[512]; - long dirID, result, length, flags; + unsigned long dirID; + long result, flags; if (HFSInitPartition(ih) == -1) return -1; - printf("Loading HFS%s file: [%s] from %x.\n", + printf("%s HFS%s file: [%s] from %x.\n", + (((offset == 0) && (length == 0)) ? "Loading" : "Reading"), (gIsHFSPlus ? "+" : ""), filePath, ih); dirID = kHFSRootFolderID; @@ -183,19 +215,22 @@ long HFSLoadFile(CICell ih, char *filePath) if ((result == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1; // Check file owner and permissions. - if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1; + if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) { + printf("%s: permissions incorrect\n", filePath); + return -1; + } - result = ReadFile(entry, &length); + result = ReadFile(entry, &length, base, offset); if (result == -1) return -1; return length; } -long HFSGetDirEntry(CICell ih, char *dirPath, long *dirIndex, char **name, - long *flags, long *time) +long HFSGetDirEntry(CICell ih, char *dirPath, unsigned long *dirIndex, + char **name, long *flags, long *time) { char entry[512]; - long dirID, dirFlags; + unsigned long dirID, dirFlags; if (HFSInitPartition(ih) == -1) return -1; @@ -226,40 +261,58 @@ long HFSGetDirEntry(CICell ih, char *dirPath, long *dirIndex, char **name, return 0; } +long HFSGetUUID(CICell ih, char *uuidStr) +{ + if (HFSInitPartition(ih) == -1) return -1; + if (gVolID == 0LL) return -1; + + return CreateUUIDString((uint8_t*)(&gVolID), sizeof(gVolID), uuidStr); +} + // Private Functions -static long ReadFile(void *file, long *length) +static long ReadFile(void *file, long *length, void *base, long offset) { void *extents; - long fileID; + unsigned long fileID; + u_int64_t fileLength; HFSCatalogFile *hfsFile = file; HFSPlusCatalogFile *hfsPlusFile = file; if (gIsHFSPlus) { fileID = hfsPlusFile->fileID; - *length = hfsPlusFile->dataFork.logicalSize; + fileLength = hfsPlusFile->dataFork.logicalSize; extents = &hfsPlusFile->dataFork.extents; } else { fileID = hfsFile->fileID; - *length = hfsFile->dataLogicalSize; + fileLength = hfsFile->dataLogicalSize; extents = &hfsFile->dataExtents; } + if (offset > fileLength) { + printf("Offset is too large.\n"); + return -1; + } + + if ((*length == 0) || ((offset + *length) > fileLength)) { + *length = (long)(fileLength - offset); + } + if (*length > kLoadSize) { printf("File is too large.\n"); return -1; } - *length = ReadExtent((char *)extents, *length, fileID, - 0, *length, (char *)kLoadAddr, 0); + *length = ReadExtent(extents, fileLength, fileID, + offset, *length, base, 0); return 0; } static long GetCatalogEntryInfo(void *entry, long *flags, long *time) { - long tmpTime; + long tmpTime = 0; // Get information about the file. switch (*(short *)entry) { @@ -271,8 +324,13 @@ static long GetCatalogEntryInfo(void *entry, long *flags, long *time) case kHFSPlusFolderRecord : *flags = kFileTypeDirectory | (((HFSPlusCatalogFolder *)entry)->bsdInfo.fileMode & kPermMask); - if (((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID != 0) + if (((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID != 0) { + static int nwarnings = 0; + if(nwarnings++ < 25) // so we don't warn for all in an Extensions walk + printf("non-root file owner detected: %d\n", + ((HFSPlusCatalogFolder *)entry)->bsdInfo.ownerID); *flags |= kOwnerNotRoot; + } tmpTime = ((HFSPlusCatalogFolder *)entry)->contentModDate; break; @@ -284,8 +342,11 @@ static long GetCatalogEntryInfo(void *entry, long *flags, long *time) case kHFSPlusFileRecord : *flags = kFileTypeFlat | (((HFSPlusCatalogFile *)entry)->bsdInfo.fileMode & kPermMask); - if (((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID != 0) + if (((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID != 0) { + printf("non-root file owner detected: %d\n", + ((HFSPlusCatalogFile *)entry)->bsdInfo.ownerID); *flags |= kOwnerNotRoot; + } tmpTime = ((HFSPlusCatalogFile *)entry)->contentModDate; break; @@ -306,11 +367,12 @@ static long GetCatalogEntryInfo(void *entry, long *flags, long *time) return 0; } -static long ResolvePathToCatalogEntry(char *filePath, long *flags, - void *entry, long dirID, long *dirIndex) +static long ResolvePathToCatalogEntry(char *filePath, long *flags, void *entry, + unsigned long dirID, unsigned long *dirIndex) { char *restPath; - long result, cnt, subFolderID, tmpDirIndex; + long result, cnt; + unsigned long subFolderID = 0, tmpDirIndex; HFSPlusCatalogFile *hfsPlusFile; // Copy the file name to gTempStr @@ -353,10 +415,12 @@ static long ResolvePathToCatalogEntry(char *filePath, long *flags, return result; } -static long GetCatalogEntry(long *dirIndex, char **name, +static long GetCatalogEntry(unsigned long *dirIndex, char **name, long *flags, long *time) { - long extentSize, nodeSize, curNode, index; + long nodeSize, index; + u_int32_t curNode; + u_int64_t extentSize; void *extent; char *nodeBuf, *testKey, *entry; BTNodeDescriptor *node; @@ -378,7 +442,7 @@ static long GetCatalogEntry(long *dirIndex, char **name, // Read the BTree node and get the record for index. ReadExtent(extent, extentSize, kHFSCatalogFileID, - curNode * nodeSize, nodeSize, nodeBuf, 1); + curNode * (u_int32_t)nodeSize, nodeSize, nodeBuf, 1); GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry); GetCatalogEntryInfo(entry, flags, time); @@ -408,8 +472,8 @@ static long GetCatalogEntry(long *dirIndex, char **name, return 0; } -static long ReadCatalogEntry(char *fileName, long dirID, - void *entry, long *dirIndex) +static long ReadCatalogEntry(char *fileName, unsigned long dirID, + void *entry, unsigned long *dirIndex) { long length; char key[sizeof(HFSPlusCatalogKey)]; @@ -434,7 +498,7 @@ static long ReadCatalogEntry(char *fileName, long dirID, return ReadBTreeEntry(kBTreeCatalog, &key, entry, dirIndex); } -static long ReadExtentsEntry(long fileID, long startBlock, void *entry) +static long ReadExtentsEntry(unsigned long fileID, unsigned long startBlock, void *entry) { char key[sizeof(HFSPlusExtentKey)]; HFSExtentKey *hfsKey = (HFSExtentKey *)key; @@ -454,16 +518,16 @@ static long ReadExtentsEntry(long fileID, long startBlock, void *entry) return ReadBTreeEntry(kBTreeExtents, &key, entry, 0); } -static long ReadBTreeEntry(long btree, void *key, char *entry, long *dirIndex) +static long ReadBTreeEntry(long btree, void *key, char *entry, unsigned long *dirIndex) { - long extentSize; + u_int64_t extentSize; void *extent; - short extentFile; + unsigned long extentFile; char *nodeBuf; BTNodeDescriptor *node; - long nodeSize, result, entrySize; - long curNode, index, lowerBound, upperBound; - char *testKey, *recordData; + long nodeSize, result = 0, entrySize = 0; + long curNode, index = 0, lowerBound, upperBound; + char *testKey, *recordData = NULL; // Figure out which tree is being looked at. if (btree == kBTreeCatalog) { @@ -492,6 +556,10 @@ static long ReadBTreeEntry(long btree, void *key, char *entry, long *dirIndex) gBTreeHeaderBuffer + btree * 256, 0); gBTHeaders[btree] = (BTHeaderRec *)(gBTreeHeaderBuffer + btree * 256 + sizeof(BTNodeDescriptor)); + if ((gIsHFSPlus && btree == kBTreeCatalog) && + (gBTHeaders[btree]->keyCompareType == kHFSBinaryCompare)) { + gCaseSensitive = 1; + } } curNode = gBTHeaders[btree]->rootNode; @@ -503,7 +571,7 @@ static long ReadBTreeEntry(long btree, void *key, char *entry, long *dirIndex) while (1) { // Read the current node. ReadExtent(extent, extentSize, extentFile, - curNode * nodeSize, nodeSize, nodeBuf, 1); + (u_int64_t)curNode * (u_int64_t)nodeSize, nodeSize, nodeBuf, 1); // Find the matching key. lowerBound = 0; @@ -596,16 +664,16 @@ static void GetBTreeRecord(long index, char *nodeBuffer, long nodeSize, } } -static long ReadExtent(char *extent, long extentSize, - long extentFile, long offset, long size, - void *buffer, long cache) +static long ReadExtent(void *extent, u_int64_t extentSize, unsigned long extentFile, + u_int64_t offset, long size, void *buffer, long cache) { - long lastOffset, blockNumber, countedBlocks = 0; - long nextExtent = 0, sizeRead = 0, readSize; - long nextExtentBlock, currentExtentBlock = 0; - long long readOffset; - long extentDensity, sizeofExtent, currentExtentSize; - char *currentExtent, *extentBuffer = 0, *bufferPos = buffer; + u_int64_t lastOffset; + unsigned long blockNumber, countedBlocks = 0, nextExtent = 0, sizeRead = 0; + u_int64_t readSize; + unsigned long nextExtentBlock, currentExtentBlock = 0; + u_int64_t readOffset; + long extentDensity, sizeofExtent, currentExtentSize; + char *currentExtent, *extentBuffer = 0, *bufferPos = buffer; if (offset >= extentSize) return 0; @@ -656,17 +724,18 @@ static long ReadExtent(char *extent, long extentSize, countedBlocks += currentExtentSize; } - readOffset = ((blockNumber - countedBlocks) * gBlockSize) + - (offset % gBlockSize); + readOffset = ((u_int64_t)(blockNumber - countedBlocks) * (u_int64_t)gBlockSize) + + (offset % gBlockSize); - readSize = GetExtentSize(currentExtent, 0) * gBlockSize - readOffset; + readSize = ((u_int64_t)GetExtentSize(currentExtent, 0) * (u_int64_t)gBlockSize) - readOffset; if (readSize > (size - sizeRead)) readSize = size - sizeRead; - readOffset += (long long)GetExtentStart(currentExtent, 0) * gBlockSize; + readOffset += (u_int64_t)GetExtentStart(currentExtent, 0) * gBlockSize; CacheRead(gCurrentIH, bufferPos, gAllocationOffset + readOffset, - readSize, cache); + (long)readSize, cache); + // truncation: readSize capped pre-CacheRead sizeRead += readSize; offset += readSize; bufferPos += readSize; @@ -677,9 +746,9 @@ static long ReadExtent(char *extent, long extentSize, return sizeRead; } -static long GetExtentStart(void *extents, long index) +static unsigned long GetExtentStart(void *extents, long index) { - long start; + unsigned long start; HFSExtentDescriptor *hfsExtents = extents; HFSPlusExtentDescriptor *hfsPlusExtents = extents; @@ -689,9 +758,9 @@ static long GetExtentStart(void *extents, long index) return start; } -static long GetExtentSize(void *extents, long index) +static unsigned long GetExtentSize(void *extents, long index) { - long size; + unsigned long size; HFSExtentDescriptor *hfsExtents = extents; HFSPlusExtentDescriptor *hfsPlusExtents = extents; @@ -704,7 +773,8 @@ static long GetExtentSize(void *extents, long index) static long CompareHFSCatalogKeys(void *key, void *testKey) { HFSCatalogKey *searchKey, *trialKey; - long result, searchParentID, trialParentID; + long result; + unsigned long searchParentID, trialParentID; searchKey = key; trialKey = testKey; @@ -726,7 +796,8 @@ static long CompareHFSCatalogKeys(void *key, void *testKey) static long CompareHFSPlusCatalogKeys(void *key, void *testKey) { HFSPlusCatalogKey *searchKey, *trialKey; - long result, searchParentID, trialParentID; + long result; + unsigned long searchParentID, trialParentID; searchKey = key; trialKey = testKey; @@ -742,10 +813,17 @@ static long CompareHFSPlusCatalogKeys(void *key, void *testKey) if ((searchKey->nodeName.length == 0) || (trialKey->nodeName.length == 0)) result = searchKey->nodeName.length - trialKey->nodeName.length; else - result = FastUnicodeCompare(&searchKey->nodeName.unicode[0], - searchKey->nodeName.length, - &trialKey->nodeName.unicode[0], - trialKey->nodeName.length); + if (gCaseSensitive) { + result = BinaryUnicodeCompare(&searchKey->nodeName.unicode[0], + searchKey->nodeName.length, + &trialKey->nodeName.unicode[0], + trialKey->nodeName.length); + } else { + result = FastUnicodeCompare(&searchKey->nodeName.unicode[0], + searchKey->nodeName.length, + &trialKey->nodeName.unicode[0], + trialKey->nodeName.length); + } } return result;