Annotation of truecrypt/boot/windows/bootmain.cpp, revision 1.1.1.5

1.1       root        1: /*
                      2:  Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
                      3: 
1.1.1.5 ! root        4:  Governed by the TrueCrypt License 2.5 the full text of which is contained
1.1       root        5:  in the file License.txt included in TrueCrypt binary and source code
                      6:  distribution packages.
                      7: */
                      8: 
                      9: #include "Crc.h"
                     10: #include "Crypto.h"
                     11: #include "Password.h"
                     12: #include "Volumes.h"
                     13: 
                     14: #include "Platform.h"
                     15: #include "Bios.h"
                     16: #include "BootConfig.h"
                     17: #include "BootMain.h"
                     18: #include "BootDefs.h"
                     19: #include "BootCommon.h"
                     20: #include "BootConsoleIo.h"
                     21: #include "BootDebug.h"
                     22: #include "BootDiskIo.h"
                     23: #include "BootEncryptedIo.h"
1.1.1.2   root       24: #include "BootMemory.h"
1.1       root       25: #include "IntFilter.h"
                     26: 
                     27: 
                     28: static void InitScreen ()
                     29: {
                     30:        ClearScreen();
                     31: 
1.1.1.5 ! root       32:        Print (
        !            33: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !            34:                " TrueCrypt Boot Loader "
        !            35: #else
        !            36:                " TrueCrypt Rescue Disk "
        !            37: #endif
        !            38:                VERSION_STRING "             Copyright (C) 2008 TrueCrypt Foundation\r\n");
1.1       root       39: 
1.1.1.5 ! root       40:        PrintRepeatedChar ('\xDC', TC_BIOS_MAX_CHARS_PER_LINE);
1.1       root       41:        PrintEndl (2);
                     42: }
                     43: 
                     44: 
                     45: static void PrintMainMenu ()
                     46: {
                     47:        Print ("    Keyboard Controls:\r\n");
1.1.1.5 ! root       48:        Print ("    [Esc]  ");
        !            49: 
        !            50: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !            51: 
        !            52:        Print ((BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) == TC_HIDDEN_OS_CREATION_PHASE_CLONING
        !            53:                ? "Postpone system cloning (boot now)"
        !            54:                : "Skip Authentication (Boot Manager)");
        !            55:        
        !            56: #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !            57: 
        !            58:        Print ("Skip Authentication (Boot Manager)");
        !            59:        Print ("\r\n    [F8]   "); Print ("Repair Options");
        !            60: 
        !            61: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1.1       root       62: 
                     63:        PrintEndl (3);
                     64: }
                     65: 
                     66: 
                     67: static bool IsMenuKey (byte scanCode)
                     68: {
1.1.1.5 ! root       69: #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1.1       root       70:        return scanCode == TC_MENU_KEY_REPAIR;
1.1.1.5 ! root       71: #else
        !            72:        return false;
        !            73: #endif
1.1       root       74: }
                     75: 
                     76: 
                     77: static bool AskYesNo (const char *message)
                     78: {
                     79:        Print (message);
                     80:        Print ("? (y/n): ");
                     81:        while (true)
                     82:        {
                     83:                switch (GetKeyboardChar())
                     84:                {
                     85:                case 'y':
                     86:                case 'Y':
1.1.1.3   root       87:                case 'z':
1.1       root       88:                        PrintEndl();
                     89:                        return true;
                     90: 
                     91:                case 'n':
                     92:                case 'N':
                     93:                        PrintEndl();
                     94:                        return false;
                     95: 
                     96:                default:
                     97:                        Beep();
                     98:                }
                     99:        }
                    100: }
                    101: 
                    102: 
                    103: static int AskSelection (const char *options[], size_t optionCount)
                    104: {
                    105:        for (int i = 0; i < optionCount; ++i)
                    106:        {
                    107:                Print ("["); Print (i + 1); Print ("]    ");
                    108:                Print (options[i]);
                    109:                PrintEndl();
                    110:        }
                    111:        Print ("[Esc]  Cancel\r\n\r\n");
                    112: 
                    113:        Print ("To select, press 1-9: ");
                    114: 
                    115:        char str;
                    116: 
                    117:        while (true)
                    118:        {
                    119:                if (GetString (&str, 1) == 0)
                    120:                        return 0;
                    121: 
                    122:                if (str >= '1' && str <= optionCount + '0')
                    123:                        return str - '0';
                    124: 
                    125:                Beep();
                    126:                PrintBackspace();
                    127:        }
                    128: }
                    129: 
                    130: 
1.1.1.5 ! root      131: static byte AskPassword (Password &password, bool hiddenSystem)
1.1       root      132: {
                    133:        size_t pos = 0;
                    134:        byte scanCode;
                    135:        byte asciiCode;
                    136: 
1.1.1.5 ! root      137:        Print ("Enter password");
        !           138:        if (PreventHiddenSystemBoot)
        !           139:                Print (hiddenSystem ? " for hidden system:\r\n" : " for decoy system:\r\n");
        !           140:        else
        !           141:                Print (": ");
1.1       root      142: 
                    143:        while (true)
                    144:        {
                    145:                asciiCode = GetKeyboardChar (&scanCode);
                    146: 
                    147:                switch (scanCode)
                    148:                {
                    149:                case TC_BIOS_KEY_ENTER:
1.1.1.2   root      150:                        ClearBiosKeystrokeBuffer();
1.1       root      151:                        PrintEndl();
1.1.1.2   root      152: 
                    153:                        password.Length = pos;
                    154:                        return scanCode;
1.1       root      155: 
                    156:                case TC_BIOS_KEY_BACKSPACE:
                    157:                        if (pos > 0)
                    158:                        {
                    159:                                if (pos < MAX_PASSWORD)
                    160:                                        PrintBackspace();
                    161:                                else
                    162:                                        PrintCharAtCusor (' ');
                    163: 
                    164:                                --pos;
                    165:                        }
                    166:                        continue;
                    167: 
                    168:                default:
                    169:                        if (scanCode == TC_BIOS_KEY_ESC || IsMenuKey (scanCode))
                    170:                        {
                    171:                                burn (password.Text, sizeof (password.Text));
1.1.1.2   root      172:                                ClearBiosKeystrokeBuffer();
                    173: 
1.1       root      174:                                PrintEndl();
                    175:                                return scanCode;
                    176:                        }
                    177:                }
                    178: 
                    179:                if (!IsPrintable (asciiCode) || pos == MAX_PASSWORD)
                    180:                {
                    181:                        Beep();
                    182:                        continue;
                    183:                }
                    184: 
                    185:                password.Text[pos++] = asciiCode;
                    186:                if (pos < MAX_PASSWORD)
                    187:                        PrintChar ('*');
                    188:                else
                    189:                        PrintCharAtCusor ('*');
                    190:        }
                    191: }
                    192: 
                    193: 
                    194: static void ExecuteBootSector (byte drive, byte *sectorBuffer)
                    195: {
                    196:        Print ("Booting...\r\n");
                    197:        CopyMemory (sectorBuffer, 0x0000, 0x7c00, TC_LB_SIZE);
1.1.1.3   root      198: 
                    199:        uint32 addr = 0x7c00;
                    200:        __asm
                    201:        {
                    202:                cli
                    203:                mov dl, drive
                    204:                xor ax, ax
                    205:                mov ds, ax
                    206:                mov es, ax
                    207:                mov ss, ax
                    208:                mov sp, 0xffff
                    209:                sti
                    210:                jmp cs:addr
                    211:        }
1.1       root      212: }
                    213: 
                    214: 
1.1.1.5 ! root      215: static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headSaltCrc32, bool skipNormal, bool skipHidden)
1.1       root      216: {
1.1.1.3   root      217:        bool status = false;
1.1.1.5 ! root      218:        bool hiddenVolume = false;
        !           219: 
1.1       root      220:        uint64 headerSec;
                    221:        headerSec.HighPart = 0;
                    222:        headerSec.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
1.1.1.5 ! root      223:        
1.1.1.3   root      224:        AcquireSectorBuffer();
1.1       root      225: 
1.1.1.5 ! root      226:        while (true)
1.1       root      227:        {
1.1.1.5 ! root      228:                if (ReadSectors (SectorBuffer, drive, headerSec, 1) != BiosResultSuccess)
        !           229:                        goto ret;
        !           230: 
        !           231:                if ((!skipNormal || hiddenVolume) && VolumeReadHeader (!hiddenVolume, (char *) SectorBuffer, &password, cryptoInfo, nullptr) == 0)
        !           232:                        status = true;
        !           233: 
1.1       root      234:                if (headSaltCrc32)
1.1.1.3   root      235:                        *headSaltCrc32 = GetCrc32 (SectorBuffer, PKCS5_SALT_SIZE);
1.1.1.5 ! root      236: 
        !           237:                if (!status && !hiddenVolume && !skipHidden && PartitionFollowingActive.Drive == drive
        !           238:                        && PartitionFollowingActive.SectorCount > ActivePartition.SectorCount)
        !           239:                {
        !           240:                        hiddenVolume = true;
        !           241:                        headerSec.LowPart = PartitionFollowingActive.StartSector.LowPart + TC_HIDDEN_VOLUME_HEADER_OFFSET / TC_LB_SIZE;
        !           242:                        continue;
        !           243:                }
        !           244: 
        !           245:                // Prevent opening of a non-system hidden volume
        !           246:                if (status && hiddenVolume && !((*cryptoInfo)->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM))
        !           247:                {
        !           248:                        status = false;
        !           249:                        crypto_close (*cryptoInfo);
        !           250:                }
        !           251: 
        !           252:                break;
1.1       root      253:        }
                    254: 
1.1.1.3   root      255: ret:
                    256:        ReleaseSectorBuffer();
                    257:        return status;
1.1       root      258: }
                    259: 
                    260: 
1.1.1.2   root      261: static bool CheckMemoryRequirements ()
                    262: {
                    263:        uint16 codeSeg;
                    264:        __asm mov codeSeg, cs
                    265:        if (codeSeg == TC_BOOT_LOADER_LOWMEM_SEGMENT)
                    266:        {
                    267:                PrintError ("Insufficient base memory: ", true, false);
                    268: 
                    269:                uint16 memFree;
                    270:                __asm
                    271:                {
                    272:                        push es
                    273:                        xor ax, ax
                    274:                        mov es, ax
                    275:                        mov ax, es:[0x413]
                    276:                        mov memFree, ax
                    277:                        pop es
                    278:                }
                    279: 
                    280:                Print (memFree); Print (" KB\r\n");
                    281: 
1.1.1.5 ! root      282:                Print ("Try disabling unneeded components (RAID, AHCI, integrated audio card, etc.) in\r\n"
        !           283:                           "BIOS setup menu (invoked by pressing Del or F2 after turning on your computer).\r\n");
        !           284: #ifndef TC_WINDOWS_BOOT_AES
        !           285:                Print ("If it does not help, try using the AES encryption algorithm to reduce memory\r\nrequirements.\r\n");
        !           286: #endif
        !           287: 
1.1.1.2   root      288:                return false;
                    289:        }
                    290: 
                    291:        return true;
                    292: }
                    293: 
                    294: 
1.1.1.5 ! root      295: static bool MountVolume (byte drive, byte &exitKey, bool skipNormal, bool skipHidden)
1.1       root      296: {
                    297:        BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
1.1.1.3   root      298:        int incorrectPasswordCount = 0;
1.1       root      299: 
1.1.1.5 ! root      300:        EraseMemory (bootArguments, sizeof (*bootArguments));
        !           301: 
1.1       root      302:        // Open volume header
                    303:        while (true)
                    304:        {
1.1.1.5 ! root      305:                exitKey = AskPassword (bootArguments->BootPassword, skipNormal);
1.1       root      306: 
                    307:                if (exitKey != TC_BIOS_KEY_ENTER)
                    308:                        return false;
                    309: 
1.1.1.5 ! root      310:                if (OpenVolume (BootDrive, bootArguments->BootPassword, &BootCryptoInfo, &bootArguments->HeaderSaltCrc32, skipNormal, skipHidden))
1.1       root      311:                        break;
                    312: 
1.1.1.5 ! root      313:                if (GetShiftFlags() & TC_BIOS_SHIFTMASK_CAPSLOCK)
        !           314:                        Print ("Warning: Caps Lock is on.\r\n");
        !           315: 
1.1.1.4   root      316:                Print ("Incorrect password.\r\n\r\n");
1.1.1.3   root      317: 
                    318:                if (++incorrectPasswordCount == 5)
                    319:                {
                    320:                        Print ("If you are sure the password is correct, the key data may be damaged. Boot your\r\n"
                    321:                                   "TrueCrypt Rescue Disk and select 'Repair Options' > 'Restore key data'.\r\n\r\n");
                    322:                }
1.1       root      323:        }
                    324: 
                    325:        // Setup boot arguments
1.1.1.5 ! root      326:        bootArguments->BootLoaderVersion = VERSION_NUM;
1.1       root      327:        bootArguments->CryptoInfoOffset = (uint16) BootCryptoInfo;
                    328:        bootArguments->CryptoInfoLength = sizeof (*BootCryptoInfo);
1.1.1.5 ! root      329:        
        !           330:        if (BootCryptoInfo->hiddenVolume)
        !           331:                bootArguments->HiddenSystemPartitionStart = PartitionFollowingActive.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
        !           332: 
1.1       root      333:        TC_SET_BOOT_ARGUMENTS_SIGNATURE (bootArguments->Signature);
                    334: 
1.1.1.5 ! root      335:        // Setup virtual encrypted partition
1.1       root      336:        if (BootCryptoInfo->EncryptedAreaLength.HighPart != 0 || BootCryptoInfo->EncryptedAreaLength.LowPart != 0)
                    337:        {
                    338:                EncryptedVirtualPartition.Drive = BootDrive;
                    339: 
1.1.1.5 ! root      340:                EncryptedVirtualPartition.StartSector = BootCryptoInfo->EncryptedAreaStart >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
        !           341:                
        !           342:                HiddenVolumeStartUnitNo = EncryptedVirtualPartition.StartSector;
        !           343:                HiddenVolumeStartSector = PartitionFollowingActive.StartSector;
        !           344:                HiddenVolumeStartSector += EncryptedVirtualPartition.StartSector;
        !           345: 
        !           346:                EncryptedVirtualPartition.SectorCount = BootCryptoInfo->EncryptedAreaLength >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
        !           347: 
        !           348:                EncryptedVirtualPartition.EndSector = EncryptedVirtualPartition.SectorCount - 1;
        !           349:                EncryptedVirtualPartition.EndSector += EncryptedVirtualPartition.StartSector;
1.1       root      350:        }
                    351:        else
                    352:        {
                    353:                // Drive not encrypted
1.1.1.5 ! root      354:                EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
1.1       root      355:        }
                    356: 
                    357:        return true;
                    358: }
                    359: 
                    360: 
                    361: static byte BootEncryptedDrive ()
                    362: {
1.1.1.3   root      363:        BootCryptoInfo = NULL;
1.1.1.5 ! root      364:        BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
1.1       root      365: 
1.1.1.5 ! root      366:        if (!GetActiveAndFollowingPartition (BootDrive))
1.1       root      367:                goto err;
                    368: 
                    369:        byte exitKey;
1.1.1.5 ! root      370:        if (!MountVolume (BootDrive, exitKey, false, PreventHiddenSystemBoot))
1.1       root      371:                return exitKey;
                    372:        
1.1.1.2   root      373:        if (!CheckMemoryRequirements ())
                    374:                goto err;
1.1.1.5 ! root      375: 
        !           376:        if (BootCryptoInfo->hiddenVolume)
        !           377:        {
        !           378:                EncryptedVirtualPartition = ActivePartition;
        !           379:                bootArguments->DecoySystemPartitionStart = ActivePartition.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
1.1.1.2   root      380:        }
                    381: 
                    382:        if (!InstallInterruptFilters())
                    383:                goto err;
1.1       root      384: 
1.1.1.5 ! root      385:        bootArguments->BootArgumentsCrc32 = GetCrc32 ((byte *) bootArguments, (byte *) &bootArguments->BootArgumentsCrc32 - (byte *) bootArguments);
        !           386: 
1.1.1.3   root      387:        while (true)
1.1       root      388:        {
1.1.1.3   root      389:                // Execute boot sector of the active partition
1.1.1.5 ! root      390:                if (ReadSectors (SectorBuffer, ActivePartition.Drive, ActivePartition.StartSector, 1) == BiosResultSuccess)
1.1.1.3   root      391:                {
1.1.1.5 ! root      392:                        ExecuteBootSector (ActivePartition.Drive, SectorBuffer);
1.1.1.3   root      393:                }
                    394: 
                    395:                GetKeyboardChar();
1.1       root      396:        }
                    397: 
                    398: err:
1.1.1.3   root      399:        if (BootCryptoInfo)
                    400:        {
                    401:                crypto_close (BootCryptoInfo);
                    402:                BootCryptoInfo = NULL;
                    403:        }
                    404: 
1.1.1.5 ! root      405:        EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
        !           406:        EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
1.1.1.2   root      407: 
1.1       root      408:        byte scanCode;
                    409:        GetKeyboardChar (&scanCode);
                    410:        return scanCode;
                    411: }
                    412: 
                    413: 
                    414: static void BootMenu ()
                    415: {
                    416:        BiosResult result;
                    417:        Partition partitions[16];
                    418:        Partition bootablePartitions[9];
                    419:        size_t partitionCount;
                    420:        size_t bootablePartitionCount = 0;
                    421: 
                    422:        for (byte drive = TC_FIRST_BIOS_DRIVE; drive <= TC_LAST_BIOS_DRIVE; ++drive)
                    423:        {
1.1.1.5 ! root      424:                if (GetDrivePartitions (drive, partitions, array_capacity (partitions), partitionCount, false, nullptr, true) == BiosResultSuccess)
1.1       root      425:                {
                    426:                        for (size_t i = 0; i < partitionCount; ++i)
                    427:                        {
                    428:                                const Partition &partition = partitions[i];
1.1.1.3   root      429:                                result = ReadSectors (SectorBuffer, drive, partition.StartSector, 1);
1.1       root      430: 
1.1.1.3   root      431:                                if (result == BiosResultSuccess && *(uint16 *) (SectorBuffer + TC_LB_SIZE - 2) == 0xaa55)
1.1       root      432:                                {
                    433:                                        // Windows writes boot loader on all NTFS/FAT filesytems it creates and, therefore,
                    434:                                        // NTFS/FAT partitions must have the boot indicator set to be considered bootable.
                    435:                                        if (!partition.Active
1.1.1.3   root      436:                                                && (*(uint32 *) (SectorBuffer + 3) == 0x5346544e  // 'NTFS'
                    437:                                                        || *(uint16 *) (SectorBuffer + 54) == 0x4146 && SectorBuffer[56] == 'T' // 'FAT'
                    438:                                                        || *(uint16 *) (SectorBuffer + 82) == 0x4146 && SectorBuffer[84] == 'T'))
1.1       root      439:                                        {
                    440:                                                continue;
                    441:                                        }
                    442: 
                    443:                                        // Bootable sector found
                    444:                                        if (bootablePartitionCount < array_capacity (bootablePartitions))
                    445:                                                bootablePartitions[bootablePartitionCount++] = partition;
                    446:                                }
                    447:                        }
                    448:                }
                    449:        }
                    450: 
                    451:        if (bootablePartitionCount < 1)
                    452:        {
                    453:                PrintError ("No bootable partition found");
                    454:                GetKeyboardChar();
                    455:                return;
                    456:        }
                    457: 
                    458:        char partChar;
                    459:        while (true)
                    460:        {
                    461:                InitScreen();
                    462:                Print ("Bootable Partitions:\r\n");
                    463:                PrintRepeatedChar ('\xC4', 20);
                    464:                Print ("\r\n");
                    465: 
                    466:                for (size_t i = 0; i < bootablePartitionCount; ++i)
                    467:                {
                    468:                        const Partition &partition = bootablePartitions[i];
                    469:                        Print ("["); Print (i + 1); Print ("]    ");
                    470:                        Print ("Drive: "); Print (partition.Drive - TC_FIRST_BIOS_DRIVE);
                    471:                        Print (", Partition: "); Print (partition.Number + 1);
1.1.1.5 ! root      472:                        Print (", Size: "); PrintSectorCountInMB (partition.SectorCount); PrintEndl();
1.1       root      473:                }
                    474: 
                    475:                if (bootablePartitionCount == 1)
                    476:                {
                    477:                        // There's only one bootable partition so we'll boot it directly instead of showing boot manager
                    478:                        partChar = '1';
                    479:                }
                    480:                else
                    481:                {
                    482:                        Print ("[Esc]  Cancel\r\n\r\n");
                    483:                        Print ("Press 1-9 to select partition: ");
                    484: 
                    485:                        if (GetString (&partChar, 1) == 0)
                    486:                                return;
                    487: 
                    488:                        PrintEndl();
                    489: 
                    490:                        if (partChar < '1' || partChar > '0' + bootablePartitionCount)
                    491:                        {
                    492:                                Beep();
                    493:                                continue;
                    494:                        }
                    495:                }
                    496: 
                    497:                const Partition &partition = bootablePartitions[partChar - '0' - 1];
                    498: 
1.1.1.3   root      499:                if (ReadSectors (SectorBuffer, partition.Drive, partition.StartSector, 1) == BiosResultSuccess)
1.1       root      500:                {
1.1.1.3   root      501:                        ExecuteBootSector (partition.Drive, SectorBuffer);
1.1       root      502:                }
                    503:        }
                    504: }
                    505: 
                    506: 
1.1.1.5 ! root      507: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !           508: 
        !           509: static bool CopyActivePartitionToHiddenVolume (byte drive, byte &exitKey)
        !           510: {
        !           511:        bool status = false;
        !           512: 
        !           513:        uint64 sectorsRemaining;
        !           514:        uint64 sectorOffset;
        !           515:        sectorOffset.LowPart = 0;
        !           516:        sectorOffset.HighPart = 0;
        !           517: 
        !           518:        int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
        !           519:        int statCount;
        !           520: 
        !           521:        if (!CheckMemoryRequirements ())
        !           522:                goto err;
        !           523: 
        !           524:        if (!GetActiveAndFollowingPartition (drive))
        !           525:                goto err;
        !           526: 
        !           527:        if (PartitionFollowingActive.Drive == TC_INVALID_BIOS_DRIVE)
        !           528:        {
        !           529:                PrintError ("No partition follows the active");
        !           530:                goto err;
        !           531:        }
        !           532: 
        !           533:        if (!MountVolume (drive, exitKey, true, false))
        !           534:                return false;
        !           535: 
        !           536:        sectorsRemaining = EncryptedVirtualPartition.SectorCount;
        !           537: 
        !           538:        if (!(sectorsRemaining == ActivePartition.SectorCount))
        !           539:        {
        !           540:                PrintError ("Hidden volume size differs from system partition");
        !           541:                crypto_close (BootCryptoInfo);
        !           542:                goto err;
        !           543:        }
        !           544: 
        !           545:        InitScreen();
        !           546:        Print ("\r\nCopying system to hidden volume. To abort, press Esc.\r\n\r\n");
        !           547: 
        !           548:        while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
        !           549:        {
        !           550:                if (EscKeyPressed())
        !           551:                {
        !           552:                        Print ("\rIf aborted, copying will have to start from the beginning (if attempted again).\r\n");
        !           553:                        if (AskYesNo ("Abort"))
        !           554:                                break;
        !           555:                }
        !           556: 
        !           557:                if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
        !           558:                        fragmentSectorCount = sectorsRemaining.LowPart;
        !           559: 
        !           560:                if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, ActivePartition.StartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
        !           561:                        break;
        !           562: 
        !           563:                AcquireSectorBuffer();
        !           564: 
        !           565:                for (int i = 0; i < fragmentSectorCount; ++i)
        !           566:                {
        !           567:                        CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
        !           568: 
        !           569:                        uint64 s = HiddenVolumeStartUnitNo + sectorOffset + i;
        !           570:                        EncryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
        !           571: 
        !           572:                        CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
        !           573:                } 
        !           574: 
        !           575:                ReleaseSectorBuffer();
        !           576: 
        !           577:                if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, HiddenVolumeStartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
        !           578:                        break;
        !           579: 
        !           580:                sectorsRemaining = sectorsRemaining - fragmentSectorCount;
        !           581:                sectorOffset = sectorOffset + fragmentSectorCount;
        !           582: 
        !           583:                if (!(statCount++ & 0xf))
        !           584:                {
        !           585:                        Print ("\rRemaining: ");
        !           586:                        PrintSectorCountInMB (sectorsRemaining);
        !           587:                }
        !           588:        }
        !           589: 
        !           590:        crypto_close (BootCryptoInfo);
        !           591: 
        !           592:        if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
        !           593:        {
        !           594:                status = true;
        !           595:                Print ("\rCopying completed.");
        !           596:        }
        !           597: 
        !           598:        PrintEndl (2);
        !           599:        goto ret;
        !           600: 
        !           601: err:
        !           602:        exitKey = TC_BIOS_KEY_ESC;
        !           603:        GetKeyboardChar();
        !           604: 
        !           605: ret:
        !           606:        EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
        !           607:        return status;
        !           608: }
        !           609: 
        !           610: 
        !           611: #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !           612: 
        !           613: 
1.1       root      614: static void DecryptDrive (byte drive)
                    615: {
                    616:        byte exitKey;
1.1.1.5 ! root      617:        if (!MountVolume (drive, exitKey, false, true))
1.1       root      618:                return;
                    619: 
1.1.1.5 ! root      620:        BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
1.1       root      621: 
                    622:        bool headerUpdateRequired = false;
                    623:        uint64 sectorsRemaining = EncryptedVirtualPartition.EndSector + 1 - EncryptedVirtualPartition.StartSector;
                    624:        uint64 sector = EncryptedVirtualPartition.EndSector + 1;
                    625: 
1.1.1.5 ! root      626:        int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
1.1       root      627:        int statCount;
                    628: 
1.1.1.5 ! root      629:        bool skipBadSectors = false;
        !           630: 
        !           631:        Print ("\r\nIMPORTANT: Use this only if Windows cannot start. Decryption under Windows is\r\n"
        !           632:                "much faster. To decrypt under Windows, run TrueCrypt and select 'System' >\r\n"
        !           633:                "'Permanently Decrypt'.\r\n\r\n");
        !           634: 
        !           635:        if (!AskYesNo ("Decrypt now"))
        !           636:        {
        !           637:                crypto_close (BootCryptoInfo);
        !           638:                goto ret;
        !           639:        }
        !           640: 
        !           641:        if (EncryptedVirtualPartition.Drive == TC_INVALID_BIOS_DRIVE)
1.1       root      642:        {
1.1.1.3   root      643:                // Drive already decrypted
1.1       root      644:                sectorsRemaining.HighPart = 0;
                    645:                sectorsRemaining.LowPart = 0;
                    646:        }
                    647:        else
                    648:        {
1.1.1.3   root      649:                Print ("\r\nTo safely interrupt and defer decryption, press Esc.\r\n"
                    650:                        "WARNING: You can turn off power only after you press Esc.\r\n\r\n");
1.1       root      651:        }
                    652: 
                    653:        while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
                    654:        {
1.1.1.5 ! root      655:                if (EscKeyPressed())
        !           656:                        break;
1.1       root      657: 
                    658:                if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
                    659:                        fragmentSectorCount = sectorsRemaining.LowPart;
                    660: 
                    661:                sector = sector - fragmentSectorCount;
                    662: 
                    663:                if (!(statCount++ & 0xf))
                    664:                {
                    665:                        Print ("\rRemaining: ");
1.1.1.5 ! root      666:                        PrintSectorCountInMB (sectorsRemaining);
1.1       root      667:                }
                    668: 
1.1.1.5 ! root      669:                if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) == BiosResultSuccess)
1.1       root      670:                {
1.1.1.5 ! root      671:                        AcquireSectorBuffer();
1.1       root      672: 
1.1.1.5 ! root      673:                        for (int i = 0; i < fragmentSectorCount; ++i)
        !           674:                        {
        !           675:                                CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
1.1       root      676: 
1.1.1.5 ! root      677:                                uint64 s = sector + i;
        !           678:                                DecryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
1.1       root      679: 
1.1.1.5 ! root      680:                                CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
        !           681:                        } 
1.1.1.3   root      682: 
1.1.1.5 ! root      683:                        ReleaseSectorBuffer();
        !           684: 
        !           685:                        if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) != BiosResultSuccess && !skipBadSectors)
        !           686:                                goto askBadSectorSkip;
        !           687:                }
        !           688:                else if (!skipBadSectors)
        !           689:                        goto askBadSectorSkip;
1.1       root      690: 
                    691:                sectorsRemaining = sectorsRemaining - fragmentSectorCount;
                    692:                headerUpdateRequired = true;
1.1.1.5 ! root      693:                continue;
        !           694: 
        !           695: askBadSectorSkip:
        !           696:                if (!AskYesNo ("Skip all bad sectors"))
        !           697:                        break;
        !           698: 
        !           699:                skipBadSectors = true;
        !           700:                sector = sector + fragmentSectorCount;
        !           701:                fragmentSectorCount = 1;
1.1       root      702:        }
                    703: 
                    704:        crypto_close (BootCryptoInfo);
                    705: 
                    706:        if (headerUpdateRequired)
                    707:        {
1.1.1.3   root      708:                AcquireSectorBuffer();
1.1       root      709:                uint64 headerSector;
                    710:                headerSector.HighPart = 0;
                    711:                headerSector.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
                    712: 
1.1.1.3   root      713:                // Update encrypted area size in volume header
1.1       root      714: 
1.1.1.3   root      715:                CRYPTO_INFO *headerCryptoInfo = crypto_open();
1.1.1.5 ! root      716:                while (ReadSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
1.1       root      717: 
1.1.1.3   root      718:                if (VolumeReadHeader (TRUE, (char *) SectorBuffer, &bootArguments->BootPassword, NULL, headerCryptoInfo) == 0)
                    719:                {
                    720:                        DecryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1.1       root      721: 
1.1.1.3   root      722:                        uint64 encryptedAreaLength = sectorsRemaining << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
1.1       root      723: 
1.1.1.3   root      724:                        for (int i = 7; i >= 0; --i)
                    725:                        {
1.1.1.5 ! root      726:                                SectorBuffer[TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH + i] = (byte) encryptedAreaLength.LowPart;
1.1.1.3   root      727:                                encryptedAreaLength = encryptedAreaLength >> 8;
1.1       root      728:                        }
                    729: 
1.1.1.5 ! root      730:                        uint32 headerCrc32 = GetCrc32 (SectorBuffer + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
        !           731: 
        !           732:                        for (i = 3; i >= 0; --i)
        !           733:                        {
        !           734:                                SectorBuffer[TC_HEADER_OFFSET_HEADER_CRC + i] = (byte) headerCrc32;
        !           735:                                headerCrc32 >>= 8;
        !           736:                        }
        !           737: 
1.1.1.3   root      738:                        EncryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1.1       root      739:                }
                    740: 
1.1.1.3   root      741:                crypto_close (headerCryptoInfo);
                    742: 
1.1.1.5 ! root      743:                while (WriteSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
1.1.1.3   root      744:                ReleaseSectorBuffer();
1.1       root      745:        }
                    746: 
1.1.1.3   root      747:        if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
                    748:                Print ("\rDrive decrypted.\r\n");
                    749:        else
                    750:                Print ("\r\nDecryption deferred.\r\n");
                    751: 
1.1       root      752:        GetKeyboardChar();
1.1.1.5 ! root      753: ret:
        !           754:        EraseMemory (bootArguments, sizeof (*bootArguments));
1.1       root      755: }
                    756: 
                    757: 
                    758: static void RepairMenu ()
                    759: {
                    760:        DriveGeometry bootLoaderDriveGeometry;
                    761:        if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry) != BiosResultSuccess)
                    762:        {
                    763:                GetKeyboardChar();
                    764:                return;
                    765:        }
                    766: 
                    767:        while (true)
                    768:        {
                    769:                InitScreen();
                    770:                Print ("Available "); Print ("Repair Options"); Print (":\r\n");
                    771:                PrintRepeatedChar ('\xC4', 25);
1.1.1.5 ! root      772:                PrintEndl();
1.1       root      773: 
                    774:                enum
                    775:                {
                    776:                        RestoreNone = 0,
                    777:                        DecryptVolume,
                    778:                        RestoreTrueCryptLoader,
                    779:                        RestoreVolumeHeader,
                    780:                        RestoreOriginalSystemLoader
                    781:                };
                    782: 
                    783:                static const char *options[] = { "Permanently decrypt system partition/drive", "Restore TrueCrypt Boot Loader", "Restore key data (volume header)", "Restore original system loader" };
                    784: 
1.1.1.5 ! root      785:                int selection = AskSelection (options,
        !           786:                        (BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER) ? array_capacity (options) : array_capacity (options) - 1);
1.1       root      787: 
                    788:                PrintEndl();
                    789: 
1.1.1.2   root      790:                switch (selection)
1.1       root      791:                {
1.1.1.2   root      792:                        case RestoreNone:
                    793:                                return;
                    794: 
                    795:                        case DecryptVolume:
1.1.1.5 ! root      796:                                DecryptDrive (BootDrive);
1.1.1.2   root      797:                                continue;
                    798: 
                    799:                        case RestoreOriginalSystemLoader:
                    800:                                if (!AskYesNo ("Is the drive decrypted"))
1.1.1.3   root      801:                                {
                    802:                                        Print ("Please decrypt it first.\r\n");
                    803:                                        GetKeyboardChar();
1.1.1.2   root      804:                                        continue;
1.1.1.3   root      805:                                }
1.1.1.4   root      806:                                break;
1.1       root      807:                }
                    808: 
                    809:                bool writeConfirmed = false;
                    810:                BiosResult result;
                    811: 
                    812:                uint64 sector;
                    813:                sector.HighPart = 0;
                    814:                ChsAddress chs;
                    815: 
1.1.1.3   root      816:                byte mbrPartTable[TC_LB_SIZE - TC_MAX_MBR_BOOT_CODE_SIZE];
                    817:                AcquireSectorBuffer();
                    818: 
1.1       root      819:                for (int i = (selection == RestoreVolumeHeader ? TC_BOOT_VOLUME_HEADER_SECTOR : TC_MBR_SECTOR);
                    820:                        i < TC_BOOT_LOADER_AREA_SECTOR_COUNT; ++i)
                    821:                {
1.1.1.5 ! root      822:                        sector.LowPart = i;
        !           823: 
        !           824:                        if (selection == RestoreOriginalSystemLoader)
        !           825:                                sector.LowPart += TC_ORIG_BOOT_LOADER_BACKUP_SECTOR;
        !           826:                        else if (selection == RestoreTrueCryptLoader)
        !           827:                                sector.LowPart += TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR;
1.1       root      828: 
                    829:                        // The backup medium may be a floppy-emulated bootable CD. The emulation may fail if LBA addressing is used.
                    830:                        // Therefore, only CHS addressing can be used.
                    831:                        LbaToChs (bootLoaderDriveGeometry, sector, chs);
                    832:                        sector.LowPart = i;
                    833: 
                    834:                        if (i == TC_MBR_SECTOR)
                    835:                        {
1.1.1.3   root      836:                                // Read current partition table
                    837:                                result = ReadSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1);
1.1       root      838:                                if (result != BiosResultSuccess)
                    839:                                        goto err;
                    840: 
1.1.1.3   root      841:                                memcpy (mbrPartTable, SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbrPartTable));
                    842:                        }
                    843: 
                    844:                        result = ReadSectors (SectorBuffer, BootLoaderDrive, chs, 1);
                    845:                        if (result != BiosResultSuccess)
                    846:                                goto err;
                    847: 
                    848:                        if (i == TC_MBR_SECTOR)
                    849:                        {
                    850:                                // Preserve current partition table
                    851:                                memcpy (SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, mbrPartTable, sizeof (mbrPartTable));
1.1       root      852:                        }
                    853: 
                    854:                        // Volume header
                    855:                        if (i == TC_BOOT_VOLUME_HEADER_SECTOR)
                    856:                        {
                    857:                                if (selection == RestoreTrueCryptLoader)
                    858:                                        continue;
                    859: 
                    860:                                if (selection == RestoreVolumeHeader)
                    861:                                {
                    862:                                        while (true)
                    863:                                        {
                    864:                                                Password password;
                    865:                                                byte exitKey = AskPassword (password);
                    866: 
                    867:                                                if (exitKey != TC_BIOS_KEY_ENTER)
                    868:                                                        goto abort;
                    869: 
                    870:                                                CRYPTO_INFO *cryptoInfo;
                    871: 
1.1.1.3   root      872:                                                CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, TC_LB_SIZE);
                    873:                                                ReleaseSectorBuffer();
                    874: 
1.1       root      875:                                                // Restore volume header only if the current one cannot be used
1.1.1.5 ! root      876:                                                if (OpenVolume (TC_FIRST_BIOS_DRIVE, password, &cryptoInfo, nullptr, false, true))
1.1       root      877:                                                {
                    878:                                                        Print ("Original header preserved.\r\n");
                    879:                                                        crypto_close (cryptoInfo);
                    880:                                                        goto err;
                    881:                                                }
                    882: 
1.1.1.3   root      883:                                                AcquireSectorBuffer();
                    884:                                                CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, 0, SectorBuffer, TC_LB_SIZE);
                    885: 
                    886:                                                if (VolumeReadHeader (TRUE, (char *) SectorBuffer, &password, &cryptoInfo, nullptr) == 0)
1.1       root      887:                                                {
                    888:                                                        crypto_close (cryptoInfo);
                    889:                                                        break;
                    890:                                                }
                    891: 
1.1.1.4   root      892:                                                Print ("Incorrect password.\r\n\r\n");
1.1       root      893:                                        }
                    894:                                }
                    895:                        }
                    896: 
1.1.1.3   root      897:                        if (!writeConfirmed && !AskYesNo ("Modify drive 0"))
1.1       root      898:                                goto abort;
                    899:                        writeConfirmed = true;
                    900: 
1.1.1.3   root      901:                        if (WriteSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1) != BiosResultSuccess)
1.1       root      902:                                goto err;
                    903:                }
                    904: done:
                    905:                switch (selection)
                    906:                {
                    907:                case RestoreTrueCryptLoader:
                    908:                        Print ("TrueCrypt Boot Loader");
                    909:                        break;
                    910: 
                    911:                case RestoreVolumeHeader:
                    912:                        Print ("Header");
                    913:                        break;
                    914: 
                    915:                case RestoreOriginalSystemLoader:
                    916:                        Print ("System loader");
                    917:                        break;
                    918:                }
                    919:                Print (" restored.\r\n");
                    920: 
                    921: err:   GetKeyboardChar();
1.1.1.3   root      922: abort: ReleaseSectorBuffer();
1.1       root      923:        }
                    924: }
                    925: 
1.1.1.5 ! root      926: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !           927: 
1.1       root      928: 
                    929: #ifndef DEBUG
                    930: extern "C" void _acrtused () { }  // Required by linker
                    931: #endif
                    932: 
                    933: 
                    934: void main ()
                    935: {
                    936:        __asm mov BootLoaderDrive, dl
                    937:        __asm mov BootSectorFlags, dh
                    938: 
1.1.1.3   root      939: #ifdef TC_BOOT_TRACING_ENABLED
1.1       root      940:        InitDebugPort();
                    941: #endif
                    942: 
1.1.1.3   root      943: #ifdef TC_BOOT_STACK_CHECKING_ENABLED
                    944:        InitStackChecker();
                    945: #endif
                    946: 
1.1.1.5 ! root      947:        InitVideoMode();
        !           948:        InitScreen();
        !           949: 
        !           950:        // Determine boot drive
1.1       root      951:        BootDrive = BootLoaderDrive;
                    952:        if (BootDrive < TC_FIRST_BIOS_DRIVE)
                    953:                BootDrive = TC_FIRST_BIOS_DRIVE;
                    954: 
1.1.1.5 ! root      955:        // Query boot drive geometry
1.1       root      956:        if (GetDriveGeometry (BootDrive, BootDriveGeometry, true) != BiosResultSuccess)
                    957:        {
                    958:                BootDrive = TC_FIRST_BIOS_DRIVE;
                    959:                if (GetDriveGeometry (BootDrive, BootDriveGeometry) == BiosResultSuccess)
                    960:                        BootDriveGeometryValid = TRUE;
                    961:        }
                    962:        else
                    963:                BootDriveGeometryValid = TRUE;
                    964: 
1.1.1.5 ! root      965: 
        !           966: #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !           967: 
        !           968:        // Check whether the user is not using the Rescue Disk to create a hidden system
        !           969: 
        !           970:        if (ReadWriteMBR (false, BootDrive, true) == BiosResultSuccess
        !           971:                && *(uint32 *) (SectorBuffer + 6) == 0x65757254
        !           972:                && *(uint32 *) (SectorBuffer + 10) == 0x70797243
        !           973:                && (SectorBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE)
        !           974:        {
        !           975:                PrintError ("It appears you are creating a hidden OS.");
        !           976:                if (AskYesNo ("Is this correct"))
        !           977:                {
        !           978:                        Print ("Please remove the Rescue Disk from the drive and restart.");
        !           979:                        while (true);
        !           980:                }
        !           981:        }
        !           982: 
        !           983: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !           984: 
        !           985: 
        !           986:        // Main menu
        !           987: 
1.1       root      988:        while (true)
                    989:        {
1.1.1.5 ! root      990:                byte exitKey;
1.1       root      991:                InitScreen();
                    992: 
1.1.1.5 ! root      993: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !           994: 
        !           995:                // Hidden system setup
        !           996:                byte hiddenSystemCreationPhase = BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
        !           997: 
        !           998:                if (hiddenSystemCreationPhase != TC_HIDDEN_OS_CREATION_PHASE_NONE)
        !           999:                {
        !          1000:                        PreventHiddenSystemBoot = true;
        !          1001:                        PrintMainMenu();
        !          1002: 
        !          1003:                        if (hiddenSystemCreationPhase == TC_HIDDEN_OS_CREATION_PHASE_CLONING)
        !          1004:                        {
        !          1005:                                if (CopyActivePartitionToHiddenVolume (BootDrive, exitKey))
        !          1006:                                {
        !          1007:                                        BootSectorFlags = (BootSectorFlags & ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) | TC_HIDDEN_OS_CREATION_PHASE_DECOY_OS;
        !          1008:                                        UpdateBootSectorConfiguration (BootLoaderDrive);
        !          1009:                                }
        !          1010:                                else if (exitKey == TC_BIOS_KEY_ESC)
        !          1011:                                        goto bootMenu;
        !          1012:                                else
        !          1013:                                        continue;
        !          1014:                        }
        !          1015:                }
        !          1016:                else
        !          1017:                        PrintMainMenu();
        !          1018: 
        !          1019:                exitKey = BootEncryptedDrive();
        !          1020: 
        !          1021: #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1.1       root     1022:                
1.1.1.5 ! root     1023:                PrintMainMenu();
        !          1024:                exitKey = BootEncryptedDrive();
        !          1025: 
1.1       root     1026:                if (exitKey == TC_MENU_KEY_REPAIR)
                   1027:                {
                   1028:                        RepairMenu();
                   1029:                        continue;
                   1030:                }
                   1031: 
1.1.1.5 ! root     1032: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
        !          1033: 
        !          1034: bootMenu:
1.1       root     1035:                BootMenu();
                   1036:        }
                   1037: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.