]> git.saurik.com Git - apple/bootx.git/blobdiff - bootx.tproj/fs.subproj/hfs.c
BootX-81.tar.gz
[apple/bootx.git] / bootx.tproj / fs.subproj / hfs.c
index ea65af48e00bd6eff5b273a54ce8978674d75518..198b4ef5f60fcf39c67e2b079136f9ee117f27a6 100644 (file)
@@ -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;