From b1faa321993abbedc0d50f45e8e7308549eead26 Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 24 Oct 2003 22:27:25 +0000 Subject: [PATCH] BootX-59.tar.gz --- bootx.tproj/ci.subproj/ci_io.c | 4 +- bootx.tproj/fs.subproj/HFSCompare.c | 35 ++++++++ bootx.tproj/fs.subproj/fs.c | 13 +++ bootx.tproj/fs.subproj/hfs.c | 26 ++++-- bootx.tproj/include.subproj/boot_args.h | 13 +++ bootx.tproj/include.subproj/libclite.h | 4 +- bootx.tproj/include.subproj/sl.h | 5 +- bootx.tproj/libclite.subproj/mem.c | 4 +- bootx.tproj/libclite.subproj/prf.c | 8 +- bootx.tproj/sl.subproj/Makefile | 2 +- bootx.tproj/sl.subproj/PB.project | 2 +- bootx.tproj/sl.subproj/drivers.c | 5 +- bootx.tproj/sl.subproj/lzss.c | 93 ++++++++++++++++++++ bootx.tproj/sl.subproj/macho.c | 3 + bootx.tproj/sl.subproj/main.c | 110 +++++++++++++++++++++--- 15 files changed, 298 insertions(+), 29 deletions(-) create mode 100644 bootx.tproj/sl.subproj/lzss.c diff --git a/bootx.tproj/ci.subproj/ci_io.c b/bootx.tproj/ci.subproj/ci_io.c index c0c9e85..e58b4f3 100644 --- a/bootx.tproj/ci.subproj/ci_io.c +++ b/bootx.tproj/ci.subproj/ci_io.c @@ -34,8 +34,10 @@ #include #include -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; } diff --git a/bootx.tproj/fs.subproj/HFSCompare.c b/bootx.tproj/fs.subproj/HFSCompare.c index 68faed6..d159c5e 100644 --- a/bootx.tproj/fs.subproj/HFSCompare.c +++ b/bootx.tproj/fs.subproj/HFSCompare.c @@ -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) diff --git a/bootx.tproj/fs.subproj/fs.c b/bootx.tproj/fs.subproj/fs.c index d4a801b..a58553b 100644 --- a/bootx.tproj/fs.subproj/fs.c +++ b/bootx.tproj/fs.subproj/fs.c @@ -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); diff --git a/bootx.tproj/fs.subproj/hfs.c b/bootx.tproj/fs.subproj/hfs.c index 1741d3f..1b30dac 100644 --- a/bootx.tproj/fs.subproj/hfs.c +++ b/bootx.tproj/fs.subproj/hfs.c @@ -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; diff --git a/bootx.tproj/include.subproj/boot_args.h b/bootx.tproj/include.subproj/boot_args.h index c206930..58a89dd 100644 --- a/bootx.tproj/include.subproj/boot_args.h +++ b/bootx.tproj/include.subproj/boot_args.h @@ -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_ */ diff --git a/bootx.tproj/include.subproj/libclite.h b/bootx.tproj/include.subproj/libclite.h index 31d9c67..a294aa2 100644 --- a/bootx.tproj/include.subproj/libclite.h +++ b/bootx.tproj/include.subproj/libclite.h @@ -41,7 +41,7 @@ #include // 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 diff --git a/bootx.tproj/include.subproj/sl.h b/bootx.tproj/include.subproj/sl.h index 952ff4c..6e30cb0 100644 --- a/bootx.tproj/include.subproj/sl.h +++ b/bootx.tproj/include.subproj/sl.h @@ -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_ */ diff --git a/bootx.tproj/libclite.subproj/mem.c b/bootx.tproj/libclite.subproj/mem.c index 9893233..d0f300f 100644 --- a/bootx.tproj/libclite.subproj/mem.c +++ b/bootx.tproj/libclite.subproj/mem.c @@ -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) diff --git a/bootx.tproj/libclite.subproj/prf.c b/bootx.tproj/libclite.subproj/prf.c index 277ec44..db95c8b 100644 --- a/bootx.tproj/libclite.subproj/prf.c +++ b/bootx.tproj/libclite.subproj/prf.c @@ -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': diff --git a/bootx.tproj/sl.subproj/Makefile b/bootx.tproj/sl.subproj/Makefile index 5fcf101..51ebbe6 100644 --- a/bootx.tproj/sl.subproj/Makefile +++ b/bootx.tproj/sl.subproj/Makefile @@ -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 diff --git a/bootx.tproj/sl.subproj/PB.project b/bootx.tproj/sl.subproj/PB.project index 3c038f2..b252f16 100644 --- a/bootx.tproj/sl.subproj/PB.project +++ b/bootx.tproj/sl.subproj/PB.project @@ -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 = (); diff --git a/bootx.tproj/sl.subproj/drivers.c b/bootx.tproj/sl.subproj/drivers.c index bfd70b6..619e7ff 100644 --- a/bootx.tproj/sl.subproj/drivers.c +++ b/bootx.tproj/sl.subproj/drivers.c @@ -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 index 0000000..579a573 --- /dev/null +++ b/bootx.tproj/sl.subproj/lzss.c @@ -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 + +#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; +} diff --git a/bootx.tproj/sl.subproj/macho.c b/bootx.tproj/sl.subproj/macho.c index 5aa36cd..c352e67 100644 --- a/bootx.tproj/sl.subproj/macho.c +++ b/bootx.tproj/sl.subproj/macho.c @@ -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. diff --git a/bootx.tproj/sl.subproj/main.c b/bootx.tproj/sl.subproj/main.c index f4b8fae..e06392c 100644 --- a/bootx.tproj/sl.subproj/main.c +++ b/bootx.tproj/sl.subproj/main.c @@ -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++; -- 2.45.2