]> git.saurik.com Git - apple/bootx.git/commitdiff
BootX-59.tar.gz mac-os-x-103 mac-os-x-1031 v59
authorApple <opensource@apple.com>
Fri, 24 Oct 2003 22:27:25 +0000 (22:27 +0000)
committerApple <opensource@apple.com>
Fri, 24 Oct 2003 22:27:25 +0000 (22:27 +0000)
15 files changed:
bootx.tproj/ci.subproj/ci_io.c
bootx.tproj/fs.subproj/HFSCompare.c
bootx.tproj/fs.subproj/fs.c
bootx.tproj/fs.subproj/hfs.c
bootx.tproj/include.subproj/boot_args.h
bootx.tproj/include.subproj/libclite.h
bootx.tproj/include.subproj/sl.h
bootx.tproj/libclite.subproj/mem.c
bootx.tproj/libclite.subproj/prf.c
bootx.tproj/sl.subproj/Makefile
bootx.tproj/sl.subproj/PB.project
bootx.tproj/sl.subproj/drivers.c
bootx.tproj/sl.subproj/lzss.c [new file with mode: 0644]
bootx.tproj/sl.subproj/macho.c
bootx.tproj/sl.subproj/main.c

index c0c9e859cc25c496288536ad1fe810ead7306117..e58b4f35f1224405a73f623128cd4dceb372f9af 100644 (file)
 #include <sl_words.h>
 #include <libclite.h>
 
-void  putchar(int ch)
+int putchar(int ch)
 {
   if ((ch == '\r') || (ch == '\n')) CallMethod(0, 0, SLWordsIH, "slw_cr");
   else CallMethod(1, 0, SLWordsIH, "slw_emit", ch);
+  
+  return ch;
 }
index 68faed6e97e50232ec721414fb55ecbd7dbadcb2..d159c5efb364757bde21f75b4da522edefb9d8fa 100644 (file)
@@ -194,6 +194,41 @@ int32_t FastUnicodeCompare (u_int16_t *str1, register u_int32_t length1,
                return 1;
 }
 
+//
+//  BinaryUnicodeCompare - Compare two Unicode strings; produce a relative ordering
+//  Compared using a 16-bit binary comparison (no case folding)
+//
+int32_t BinaryUnicodeCompare (u_int16_t * str1, u_int32_t length1,
+                             u_int16_t * str2, u_int32_t length2)
+{
+       register u_int16_t c1, c2;
+       int32_t bestGuess;
+       u_int32_t length;
+
+       bestGuess = 0;
+
+       if (length1 < length2) {
+               length = length1;
+               --bestGuess;
+       } else if (length1 > length2) {
+               length = length2;
+               ++bestGuess;
+       } else {
+               length = length1;
+       }
+
+       while (length--) {
+               c1 = *(str1++);
+               c2 = *(str2++);
+
+               if (c1 > c2)
+                       return (1);
+               if (c1 < c2)
+                       return (-1);
+       }
+
+       return (bestGuess);
+}
 
 /*
  * UTF-8 (UCS Transformation Format)
index d4a801bc21a6d47159bf29c83d8aa57d6a41a34d..a58553b64a8325a846028a3cb585a61760fa8308 100644 (file)
@@ -53,6 +53,7 @@ typedef struct PartInfo PartInfo, *PartInfoPtr;
 
 #define kNumPartInfos  (16)
 static PartInfo gParts[kNumPartInfos];
+static char gMakeDirSpec[1024];
 
 // Private function prototypes
 long LookupPartition(char *devSpec);
@@ -86,6 +87,18 @@ long GetFileInfo(char *dirSpec, char *name, long *flags, long *time)
 {
   long ret, index = 0;
   char *curName;
+
+  if (!dirSpec) {
+    long       idx, len;
+
+    len = strlen(name);
+
+    for (idx = len; idx && (name[idx] != '\\'); idx--) {}
+    idx++;
+    strncpy(gMakeDirSpec, name, idx);
+    name += idx;
+    dirSpec = gMakeDirSpec;
+  }
   
   while (1) {
     ret = GetDirEntry(dirSpec, &index, &curName, flags, time);
index 1741d3f95816ef685f0fe5347f30ccff82467055..1b30dacac5712563992af83187c53328b28fe71e 100644 (file)
@@ -43,6 +43,7 @@
 static CICell                  gCurrentIH;
 static long long               gAllocationOffset;
 static long                    gIsHFSPlus;
+static long                    gCaseSensitive;
 static long                    gBlockSize;
 static char                    gBTreeHeaderBuffer[512];
 static BTHeaderRec             *gBTHeaders[2];
@@ -82,6 +83,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,
@@ -99,6 +102,7 @@ long HFSInitPartition(CICell ih)
   
   gAllocationOffset = 0;
   gIsHFSPlus = 0;
+  gCaseSensitive = 0;
   gBTHeaders[0] = 0;
   gBTHeaders[1] = 0;
   
@@ -139,7 +143,8 @@ long HFSInitPartition(CICell ih)
   Read(ih, (long)gHFSPlusHeader, kBlockSize);
   
   // Not a HFS[+] volume.
-  if (gHFSPlus->signature != kHFSPlusSigWord) return -1;
+  if ((gHFSPlus->signature != kHFSPlusSigWord) &&
+      (gHFSPlus->signature != kHFSXSigWord)) return -1;
   
   gIsHFSPlus = 1;
   gBlockSize = gHFSPlus->blockSize;
@@ -495,6 +500,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;
@@ -745,10 +754,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;
index c20693009970f6cf6c8e572485085afa40daa20a..58a89dd254427c1f993051d0375fe2eb5e216567 100644 (file)
@@ -77,4 +77,17 @@ struct boot_args {
 };
 typedef struct boot_args boot_args, *boot_args_ptr;
 
+struct compressed_kernel_header {
+  u_int32_t signature;
+  u_int32_t compress_type;
+  u_int32_t adler32;
+  u_int32_t uncompressed_size;
+  u_int32_t compressed_size;
+  u_int32_t reserved[11];
+  char      platform_name[64];
+  char      root_path[256];
+  u_int8_t  data[0];
+};
+typedef struct compressed_kernel_header compressed_kernel_header;
+
 #endif /* ! _BOOTX_BOOT_ARGS_H_ */
index 31d9c6721751e5a27629fa40e57cc3aab4fe3227..a294aa2870a9cec5c59da4bf9a71e352b2aee1a9 100644 (file)
@@ -41,7 +41,7 @@
 #include <stddef.h>
 
 // ci_io.c
-extern void  putchar(int ch);
+extern int putchar(int ch);
 
 // prf.c
 extern void prf(const char *fmt, unsigned int *adx, void (*putfn_p)(),
@@ -83,7 +83,7 @@ extern void *realloc(void *start, size_t newsize);
 // mem.c
 extern void *memcpy(void *dst, const void *src, size_t len);
 extern void *memset(void *dst, int ch, size_t len);
-extern void *bcopy(void *src, void *dst, int len);
+extern void bcopy(const void *src, void *dst, size_t len);
 extern void bzero(void *dst, int len);
 
 // bsearch.c
index 952ff4cc9adc5fb0deb3c77f2dffbc4483d7caed..6e30cb0b372f2c1419a203da870c2885e678ac6a 100644 (file)
@@ -159,9 +159,9 @@ extern long gSymbolTableSize;
 extern long gBootMode;
 extern long gBootDeviceType;
 extern long gBootFileType;
+extern char gHaveKernelCache;
 extern char gBootDevice[256];
 extern char gBootFile[256];
-extern char gRootDir[256];
 
 extern char gTempStr[4096];
 
@@ -220,4 +220,7 @@ extern long LoadDrivers(char *dirPath);
 extern long InitConfig(void);
 extern long ParseConfigFile(char *addr);
 
+// Externs for lzss.c
+extern int decompress_lzss(u_int8_t *dst, u_int8_t *src, u_int32_t srclen);
+
 #endif /* ! _BOOTX_SL_H_ */
index 98932331f18c8959d63d307ad707c0117448c0bf..d0f300ffbfab4be8e0b278a75ea9e054f338a494 100644 (file)
@@ -79,9 +79,9 @@ void *memset(void *dst, int ch, size_t len)
   return dst;
 }
 
-void *bcopy(void *src, void *dst, int len)
+void bcopy(const void *src, void *dst, size_t len)
 {
-  return memcpy(dst, src, len);
+  memcpy(dst, src, len);
 }
 
 void bzero(void *dst, int len)
index 277ec441e1628dd2e00c29a01ff45581a8d181d6..db95c8b8ef6125d7456963a918d891ddc92de4a0 100644 (file)
@@ -50,6 +50,7 @@
 
 #define SPACE  1
 #define ZERO   2
+#define UCASE  16
 
 /*
  * Scaled down version of C Library printf.
@@ -80,7 +81,7 @@ printn(n, b, flag, minwidth, putfn_p, putfn_arg)
        }
        cp = prbuf;
        do {
-               *cp++ = "0123456789abcdef"[n%b];
+               *cp++ = "0123456789abcdef0123456789ABCDEF"[(flag & UCASE) + n%b];
                n /= b;
                width++;
        } while (n);
@@ -140,7 +141,10 @@ again:
                minwidth *= 10;
                minwidth += c - '0';
                goto again;
-       case 'x': case 'X':
+       case 'X':
+               flag |= UCASE;
+               /* fall through */
+       case 'x':
                b = 16;
                goto number;
        case 'd':
index 5fcf101d73e635f901b564a1cd081767b6b4ce6a..51ebbe69cd1345e2d60bb2a3bdc9a7171cc4d9c6 100644 (file)
@@ -14,7 +14,7 @@ PROJECT_TYPE = Component
 
 HFILES = appleboot.h clut.h elf.h failedboot.h netboot.h
 
-CFILES = main.c macho.c device_tree.c display.c drivers.c elf.c
+CFILES = main.c macho.c device_tree.c display.c drivers.c elf.c lzss.c
 
 OTHERSRCS = Makefile.preamble Makefile Makefile.postamble
 
index 3c038f26054c85ce02f2941fe1a0927d2c188459..b252f1657d582ca137a8fd4d951d803ec1531993 100644 (file)
@@ -14,7 +14,7 @@
             netboot.h 
         ); 
         M_FILES = (); 
-        OTHER_LINKED = (main.c, macho.c, device_tree.c, display.c, elf.c, drivers.c); 
+        OTHER_LINKED = (main.c, macho.c, device_tree.c, display.c, elf.c, drivers.c, lzss.c); 
         OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble); 
         SUBPROJECTS = (); 
         TOOLS = (); 
index bfd70b6219f643ebf00259171512cbcb67224d99..619e7ffc8a32ff4ca27590a904bb050d12566049 100644 (file)
@@ -141,7 +141,6 @@ static void DumpTag(TagPtr tag, long depth);
 
 static ModulePtr gModuleHead, gModuleTail;
 static TagPtr    gPersonalityHead, gPersonalityTail;
-static char      gExtensionsSpec[4096];
 static char      gDriverSpec[4096];
 static char      gFileSpec[4096];
 static char      gTempSpec[4096];
@@ -154,9 +153,7 @@ long LoadDrivers(char *dirSpec)
   if (gBootFileType == kNetworkDeviceType) {
     NetLoadDrivers(dirSpec);
   } else if (gBootFileType == kBlockDeviceType) {
-    strcpy(gExtensionsSpec, dirSpec);
-    strcat(gExtensionsSpec, "System\\Library\\");
-    FileLoadDrivers(gExtensionsSpec, 0);
+    FileLoadDrivers(dirSpec, 0);
   } else {
     return 0;
   }
diff --git a/bootx.tproj/sl.subproj/lzss.c b/bootx.tproj/sl.subproj/lzss.c
new file mode 100644 (file)
index 0000000..579a573
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 
+ * 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. 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/**************************************************************
+ LZSS.C -- A Data Compression Program
+***************************************************************
+    4/6/1989 Haruhiko Okumura
+    Use, distribute, and modify this program freely.
+    Please send me your improved versions.
+        PC-VAN      SCIENCE
+        NIFTY-Serve PAF01022
+        CompuServe  74050,1022
+
+**************************************************************/
+/*
+ *  lzss.c - Package for decompressing lzss compressed objects
+ *
+ *  Copyright (c) 2003 Apple Computer, Inc.
+ *
+ *  DRI: Josh de Cesare
+ */
+
+#include <sl.h>
+
+#define N         4096  /* size of ring buffer - must be power of 2 */
+#define F         18    /* upper limit for match_length */
+#define THRESHOLD 2     /* encode string into position and length
+                           if match_length is greater than this */
+#define NIL       N     /* index for root of binary search trees */
+
+int
+decompress_lzss(u_int8_t *dst, u_int8_t *src, u_int32_t srclen)
+{
+    /* ring buffer of size N, with extra F-1 bytes to aid string comparison */
+    u_int8_t text_buf[N + F - 1];
+    u_int8_t *dststart = dst;
+    u_int8_t *srcend = src + srclen;
+    int  i, j, k, r, c;
+    unsigned int flags;
+    
+    dst = dststart;
+    srcend = src + srclen;
+    for (i = 0; i < N - F; i++)
+        text_buf[i] = ' ';
+    r = N - F;
+    flags = 0;
+    for ( ; ; ) {
+        if (((flags >>= 1) & 0x100) == 0) {
+            if (src < srcend) c = *src++; else break;
+            flags = c | 0xFF00;  /* uses higher byte cleverly */
+        }   /* to count eight */
+        if (flags & 1) {
+            if (src < srcend) c = *src++; else break;
+            *dst++ = c;
+            text_buf[r++] = c;
+            r &= (N - 1);
+        } else {
+            if (src < srcend) i = *src++; else break;
+            if (src < srcend) j = *src++; else break;
+            i |= ((j & 0xF0) << 4);
+            j  =  (j & 0x0F) + THRESHOLD;
+            for (k = 0; k <= j; k++) {
+                c = text_buf[(i + k) & (N - 1)];
+                *dst++ = c;
+                text_buf[r++] = c;
+                r &= (N - 1);
+            }
+        }
+    }
+    
+    return dst - dststart;
+}
index 5aa36cd1bbdd872cf9ae43ed4e7770e0987ed2af..c352e67513c88b64d8d407f660ccbdd659f5b5ed 100644 (file)
@@ -171,6 +171,9 @@ static long DecodeSegment(long cmdBase)
   // Add the Segment to the memory-map.
   sprintf(rangeName, "Kernel-%s", segCmd->segname);
   AllocateMemoryRange(rangeName, (long)vmaddr, vmsize);
+
+  if (vmsize && (strcmp(segCmd->segname, "__PRELINK") == 0))
+    gHaveKernelCache = 1;
   
   // Handle special segments first.
   
index f4b8fae9ae396ce05f45cdce0986c86529ff74e2..e06392c55d1f65c07b4e89c50d98c54a382b4e9c 100644 (file)
@@ -65,9 +65,13 @@ long gBootSourceNumberMax;
 long gBootMode = kBootModeNormal;
 long gBootDeviceType;
 long gBootFileType;
+char gHaveKernelCache = 0;
 char gBootDevice[256];
 char gBootFile[256];
-char gRootDir[256];
+static char gBootKernelCacheFile[512];
+static char gExtensionsSpec[4096];
+static char gCacheNameAdler[64 + sizeof(gBootFile)];
+static char *gPlatformName = gCacheNameAdler;
 
 char gTempStr[4096];
 
@@ -115,6 +119,8 @@ static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr)
 static void Main(ClientInterfacePtr ciPtr)
 {
   long ret;
+  int  trycache;
+  long flags, cachetime, time;
   
   ret = InitEverything(ciPtr);
   if (ret != 0) Exit();
@@ -126,18 +132,53 @@ static void Main(ClientInterfacePtr ciPtr)
   DrawSplashScreen(0);
   
   while (ret == 0) {
+    trycache = (0 == (gBootMode & kBootModeSafe))
+             && (gBootKernelCacheFile[0] != 0);
+    
+    if (trycache && (gBootFileType == kBlockDeviceType)) do {
+      
+      // if we haven't found the kernel yet, don't use the cache
+      ret = GetFileInfo(NULL, gBootFile, &flags, &time);
+      if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
+       trycache = 0;
+       break;
+      }
+      ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
+      if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
+        || (cachetime < time)) {
+       trycache = 0;
+       break;
+      }
+      ret = GetFileInfo(gExtensionsSpec, "Extensions", &flags, &time);
+      if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
+       && (cachetime < time)) {
+       trycache = 0;
+       break;
+      }
+    } while (0);
+    
+    if (trycache) {
+      ret = LoadFile(gBootKernelCacheFile);
+      if (ret != -1) {
+        ret = DecodeKernel();
+        if (ret != -1) break;
+      }
+    }
     ret = LoadFile(gBootFile);
+    if (ret != -1)
+      ret = DecodeKernel();
     if (ret != -1) break;
     
     ret = GetBootPaths();
     if (ret != 0) FailToBoot(2);
   }
   
-  ret = DecodeKernel();
   if (ret != 0) FailToBoot(3);
   
-  ret = LoadDrivers(gRootDir);
-  if (ret != 0) FailToBoot(4);
+  if (!gHaveKernelCache) {
+    ret = LoadDrivers(gExtensionsSpec);
+    if (ret != 0) FailToBoot(4);
+  }
   
   DrawSplashScreen(1);
   
@@ -155,6 +196,8 @@ static long InitEverything(ClientInterfacePtr ciPtr)
   long   ret, mem_base, mem_base2, size;
   CICell keyboardPH;
   char   name[32], securityMode[33];
+  long length;
+  char *compatible;
   
   // Init the OF Client Interface.
   ret = InitCI(ciPtr);
@@ -197,6 +240,11 @@ static long InitEverything(ClientInterfacePtr ciPtr)
     return -1;
   }
   
+  // Get first element of root's compatible property.
+  ret = GetPackageProperty(Peer(0), "compatible", &compatible, &length);
+  if (ret != -1)
+    strcpy(gPlatformName, compatible);
+  
   // Get stdout's IH, so that the boot display can be found.
   ret = GetProp(gChosenPH, "stdout", (char *)&gStdOutIH, 4);
   if (ret == 4) gStdOutPH = InstanceToPackage(gStdOutIH);
@@ -334,11 +382,34 @@ long ThinFatBinary(void **binary, unsigned long *length)
   return ret;
 }
 
-
 static long DecodeKernel(void)
 {
   void *binary = (void *)kLoadAddr;
   long ret;
+  compressed_kernel_header * kernel_header = (compressed_kernel_header *) kLoadAddr;
+  u_int32_t size;
+  
+  if (kernel_header->signature == 'comp') {
+    if (kernel_header->compress_type != 'lzss')
+      return -1;
+    if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name))
+      return -1;
+    if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path))
+      return -1;
+    
+    binary = AllocateBootXMemory(kernel_header->uncompressed_size);
+    
+    size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0], kernel_header->compressed_size);
+    if (kernel_header->uncompressed_size != size) {
+      printf("size mismatch from lzss %x\n", size);
+      return -1;
+    }
+    if (kernel_header->adler32 !=
+       Alder32(binary, kernel_header->uncompressed_size)) {
+      printf("adler mismatch\n");
+      return -1;
+    }
+  }
   
   ThinFatBinary(&binary, 0);
   
@@ -740,6 +811,7 @@ static long TestForKey(long key)
 static long GetBootPaths(void)
 {
   long ret, cnt, cnt2, cnt3, cnt4, size, partNum, bootplen, bsdplen;
+  unsigned long adler32;
   char *filePath, *buffer;
   
   if (gBootSourceNumber == -1) {
@@ -870,8 +942,18 @@ static long GetBootPaths(void)
       strncpy(gBootFile, gBootDevice, cnt + 1);
       sprintf(gBootFile + cnt + 1, "%d,%s\\mach_kernel",
              partNum, ((gBootSourceNumber & 1) ? "" : "\\"));
+
+      // and the cache file name
+
+      bzero(gCacheNameAdler + 64, sizeof(gBootFile));
+      strcpy(gCacheNameAdler + 64, gBootFile);
+      adler32 = Alder32(gCacheNameAdler, sizeof(gCacheNameAdler));
+
+      strncpy(gBootKernelCacheFile, gBootDevice, cnt + 1);
+      sprintf(gBootKernelCacheFile + cnt + 1, 
+               "%d,\\System\\Library\\Caches\\com.apple.kernelcaches\\kernelcache.%08lX", partNum, adler32);
       break;
-      
+
     default:
       printf("Failed to infer Boot Device Type.\n");
       return -1;
@@ -880,10 +962,10 @@ static long GetBootPaths(void)
   }
   
   // Figure out the root dir.
-  ret = ConvertFileSpec(gBootFile, gRootDir, &filePath);
+  ret = ConvertFileSpec(gBootFile, gExtensionsSpec, &filePath);
   if (ret == -1) return -1;
   
-  strcat(gRootDir, ",");
+  strcat(gExtensionsSpec, ",");
   
   // Add in any extra path to gRootDir.
   cnt = 0;
@@ -892,12 +974,20 @@ static long GetBootPaths(void)
   if (cnt != 0) {
     for (cnt2 = cnt - 1; cnt2 >= 0; cnt2--) {
       if (filePath[cnt2] == '\\') {
-       strncat(gRootDir, filePath, cnt2 + 1);
+       strncat(gExtensionsSpec, filePath, cnt2 + 1);
        break;
       }
     }
   }
-  
+
+  // Figure out the extensions dir.
+  if (gBootFileType == kBlockDeviceType) {
+    cnt = strlen(gExtensionsSpec);
+    if ((cnt > 2) && (gExtensionsSpec[cnt-1] == '\\') && (gExtensionsSpec[cnt-2] == '\\'))
+       cnt--;
+    strcpy(gExtensionsSpec + cnt, "System\\Library\\");
+  }
+
   SetProp(gChosenPH, "rootpath", gBootFile, strlen(gBootFile) + 1);
   
   gBootSourceNumber++;