/*
- * 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
*/
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];
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);
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,
long HFSInitPartition(CICell ih)
{
- long extentSize, extentFile, nodeSize;
+ unsigned long extentFile;
+ long nodeSize;
+ u_int64_t extentSize;
void *extent;
if (ih == gCurrentIH) return 0;
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) {
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;
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;
}
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;
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;
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) {
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;
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;
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
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;
// 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);
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)];
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;
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) {
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;
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;
}
}
-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;
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;
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;
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;
static long CompareHFSCatalogKeys(void *key, void *testKey)
{
HFSCatalogKey *searchKey, *trialKey;
- long result, searchParentID, trialParentID;
+ long result;
+ unsigned long searchParentID, trialParentID;
searchKey = key;
trialKey = 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;
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;