|
|
1.1 ! root 1: /* ! 2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved. ! 3: ! 4: Governed by the TrueCrypt License 2.4 the full text of which is contained ! 5: in the file License.txt included in TrueCrypt binary and source code ! 6: distribution packages. ! 7: */ ! 8: ! 9: #include "Tcdefs.h" ! 10: ! 11: #include "Inflate.h" ! 12: #include "SelfExtract.h" ! 13: #include "Wizard.h" ! 14: #include "Setup.h" ! 15: #include "Crc.h" ! 16: #include "Endian.h" ! 17: #include "Dlgcode.h" ! 18: #include "Dir.h" ! 19: #include "Language.h" ! 20: #include "Resource.h" ! 21: ! 22: #define OutputPackageFile "TrueCrypt Setup " VERSION_STRING ".exe" ! 23: ! 24: #define MAG_START_MARKER "TCINSTRT" ! 25: #define MAG_END_MARKER_OBFUSCATED "T/C/I/N/S/C/R/C" ! 26: #define PIPE_BUFFER_LEN (4 * BYTES_PER_KB) ! 27: ! 28: unsigned char MagEndMarker [sizeof (MAG_END_MARKER_OBFUSCATED)]; ! 29: char DestExtractPath [TC_MAX_PATH]; ! 30: DECOMPRESSED_FILE Decompressed_Files [NBR_COMPRESSED_FILES]; ! 31: ! 32: volatile char *PipeWriteBuf = NULL; ! 33: volatile HANDLE hChildStdinWrite = INVALID_HANDLE_VALUE; ! 34: unsigned char *DecompressedData = NULL; ! 35: ! 36: ! 37: ! 38: void SelfExtractStartupInit (void) ! 39: { ! 40: DeobfuscateMagEndMarker (); ! 41: } ! 42: ! 43: ! 44: // The end marker must be included in the self-extracting exe only once, not twice (used e.g. ! 45: // by IsSelfExtractingPackage()) and that's why MAG_END_MARKER_OBFUSCATED is obfuscated and ! 46: // needs to be deobfuscated using this function at startup. ! 47: static void DeobfuscateMagEndMarker (void) ! 48: { ! 49: int i; ! 50: ! 51: for (i = 0; i < sizeof (MAG_END_MARKER_OBFUSCATED); i += 2) ! 52: MagEndMarker [i/2] = MAG_END_MARKER_OBFUSCATED [i]; ! 53: ! 54: MagEndMarker [i/2] = 0; ! 55: } ! 56: ! 57: ! 58: static void PkgError (char *msg) ! 59: { ! 60: MessageBox (NULL, msg, "TrueCrypt", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); ! 61: } ! 62: ! 63: ! 64: static void PkgWarning (char *msg) ! 65: { ! 66: MessageBox (NULL, msg, "TrueCrypt", MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST); ! 67: } ! 68: ! 69: ! 70: static void PkgInfo (char *msg) ! 71: { ! 72: MessageBox (NULL, msg, "TrueCrypt", MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST); ! 73: } ! 74: ! 75: ! 76: // Returns 0 if decompression fails or, if successful, returns the size of the decompressed data ! 77: static int DecompressBuffer (char *out, char *in, int len) ! 78: { ! 79: return (DecompressDeflatedData (out, in, len)); // Inflate ! 80: } ! 81: ! 82: ! 83: static void __cdecl PipeWriteThread (void *len) ! 84: { ! 85: int sendBufSize = PIPE_BUFFER_LEN, bytesSent = 0; ! 86: int bytesToSend = *((int *) len), bytesSentTotal = 0; ! 87: ! 88: if (PipeWriteBuf == NULL || (HANDLE) hChildStdinWrite == INVALID_HANDLE_VALUE) ! 89: { ! 90: PkgError ("Failed sending data to the STDIN pipe"); ! 91: return; ! 92: } ! 93: ! 94: while (bytesToSend > 0) ! 95: { ! 96: if (bytesToSend < PIPE_BUFFER_LEN) ! 97: sendBufSize = bytesToSend; ! 98: ! 99: if (!WriteFile ((HANDLE) hChildStdinWrite, (char *) PipeWriteBuf + bytesSentTotal, sendBufSize, &bytesSent, NULL) ! 100: || bytesSent == 0 ! 101: || bytesSent != sendBufSize) ! 102: { ! 103: PkgError ("Failed sending data to the STDIN pipe"); ! 104: return; ! 105: } ! 106: ! 107: bytesToSend -= bytesSent; ! 108: bytesSentTotal += bytesSent; ! 109: } ! 110: ! 111: // Closing the pipe causes the child process to stop reading from it ! 112: ! 113: if (!CloseHandle (hChildStdinWrite)) ! 114: { ! 115: PkgError ("Cannot close pipe"); ! 116: return; ! 117: } ! 118: } ! 119: ! 120: ! 121: // Returns 0 if compression fails or, if successful, the size of the compressed data ! 122: static int CompressBuffer (char *out, char *in, int len) ! 123: { ! 124: SECURITY_ATTRIBUTES securityAttrib; ! 125: DWORD bytesReceived = 0; ! 126: HANDLE hChildStdoutWrite = INVALID_HANDLE_VALUE; ! 127: HANDLE hChildStdoutRead = INVALID_HANDLE_VALUE; ! 128: HANDLE hChildStdinRead = INVALID_HANDLE_VALUE; ! 129: STARTUPINFO startupInfo; ! 130: PROCESS_INFORMATION procInfo; ! 131: char pipeBuffer [PIPE_BUFFER_LEN]; ! 132: int res_len = 0; ! 133: BOOL bGzipHeaderRead = FALSE; ! 134: ! 135: ZeroMemory (&startupInfo, sizeof (startupInfo)); ! 136: ZeroMemory (&procInfo, sizeof (procInfo)); ! 137: ! 138: // Pipe handle inheritance ! 139: securityAttrib.bInheritHandle = TRUE; ! 140: securityAttrib.nLength = sizeof (securityAttrib); ! 141: securityAttrib.lpSecurityDescriptor = NULL; ! 142: ! 143: if (!CreatePipe (&hChildStdoutRead, &hChildStdoutWrite, &securityAttrib, 0)) ! 144: { ! 145: PkgError ("Cannot create STDOUT pipe."); ! 146: return 0; ! 147: } ! 148: SetHandleInformation (hChildStdoutRead, HANDLE_FLAG_INHERIT, 0); ! 149: ! 150: if (!CreatePipe (&hChildStdinRead, &((HANDLE) hChildStdinWrite), &securityAttrib, 0)) ! 151: { ! 152: PkgError ("Cannot create STDIN pipe."); ! 153: return 0; ! 154: } ! 155: SetHandleInformation (hChildStdinWrite, HANDLE_FLAG_INHERIT, 0); ! 156: ! 157: // Create a child process that will compress the data ! 158: ! 159: startupInfo.wShowWindow = SW_HIDE; ! 160: startupInfo.hStdInput = hChildStdinRead; ! 161: startupInfo.hStdOutput = hChildStdoutWrite; ! 162: startupInfo.cb = sizeof (startupInfo); ! 163: startupInfo.hStdError = hChildStdoutWrite; ! 164: startupInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; ! 165: ! 166: if (!CreateProcess (NULL, "gzip --best", NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &procInfo)) ! 167: { ! 168: PkgError ("Error: Cannot run gzip.\n\nBefore you can create a self-extracting TrueCrypt package, you need to have the open-source 'gzip' compression tool placed in any directory in the search path for executable files (for example, in 'C:\\Windows\\').\n\nNote: gzip can be freely downloaded e.g. from www.gzip.org"); ! 169: return 0; ! 170: } ! 171: ! 172: CloseHandle (procInfo.hProcess); ! 173: CloseHandle (procInfo.hThread); ! 174: ! 175: // Start sending the uncompressed data to the pipe (STDIN) ! 176: PipeWriteBuf = in; ! 177: _beginthread (PipeWriteThread, PIPE_BUFFER_LEN * 2, (void *) &len); ! 178: ! 179: if (!CloseHandle (hChildStdoutWrite)) ! 180: { ! 181: PkgError ("Cannot close STDOUT write"); ! 182: return 0; ! 183: } ! 184: ! 185: bGzipHeaderRead = FALSE; ! 186: ! 187: // Read the compressed data from the pipe (sent by the child process to STDOUT) ! 188: while (TRUE) ! 189: { ! 190: if (!ReadFile (hChildStdoutRead, pipeBuffer, bGzipHeaderRead ? PIPE_BUFFER_LEN : 10, &bytesReceived, NULL)) ! 191: break; ! 192: ! 193: if (bGzipHeaderRead) ! 194: { ! 195: memcpy (out + res_len, pipeBuffer, bytesReceived); ! 196: res_len += bytesReceived; ! 197: } ! 198: else ! 199: bGzipHeaderRead = TRUE; // Skip the 10-byte gzip header ! 200: } ! 201: return res_len - 8; // A gzip stream ends with a CRC-32 hash and a 32-bit size (those 8 bytes need to be chopped off) ! 202: } ! 203: ! 204: ! 205: // Clears all bytes that change when an exe file is digitally signed, except the data that are appended. ! 206: // If those bytes weren't cleared, CRC-32 checks would fail after signing. ! 207: static void WipeSignatureAreas (char *buffer) ! 208: { ! 209: buffer [0x130] = 0; ! 210: buffer [0x131] = 0; ! 211: buffer [0x132] = 0; ! 212: ! 213: buffer [0x138] = 0; ! 214: buffer [0x139] = 0; ! 215: buffer [0x13A] = 0; ! 216: ! 217: buffer [0x170] = 0; ! 218: buffer [0x171] = 0; ! 219: buffer [0x172] = 0; ! 220: buffer [0x173] = 0; ! 221: buffer [0x174] = 0; ! 222: buffer [0x175] = 0; ! 223: ! 224: buffer [0x178] = 0; ! 225: buffer [0x179] = 0; ! 226: buffer [0x17A] = 0; ! 227: buffer [0x17B] = 0; ! 228: buffer [0x17C] = 0; ! 229: buffer [0x17D] = 0; ! 230: } ! 231: ! 232: ! 233: BOOL MakeSelfExtractingPackage (HWND hwndDlg, char *szDestDir) ! 234: { ! 235: int i, x; ! 236: unsigned char inputFile [TC_MAX_PATH]; ! 237: unsigned char outputFile [TC_MAX_PATH]; ! 238: unsigned char szTmpFilePath [TC_MAX_PATH]; ! 239: unsigned char szTmp32bit [4] = {0}; ! 240: unsigned char *szTmp32bitPtr = szTmp32bit; ! 241: unsigned char *buffer = NULL, *compressedBuffer = NULL; ! 242: unsigned char *bufIndex = NULL; ! 243: char tmpStr [2048]; ! 244: int bufLen = 0, compressedDataLen = 0, uncompressedDataLen = 0; ! 245: ! 246: x = strlen (szDestDir); ! 247: if (x < 2) ! 248: return FALSE; ! 249: ! 250: if (szDestDir[x - 1] != '\\') ! 251: strcat (szDestDir, "\\"); ! 252: ! 253: GetModuleFileName (NULL, inputFile, sizeof (inputFile)); ! 254: ! 255: strcpy (outputFile, szDestDir); ! 256: strncat (outputFile, OutputPackageFile, sizeof (outputFile) - strlen (outputFile) - 1); ! 257: ! 258: // Clone 'TrueCrypt Setup.exe' to create the base of the new self-extracting archive ! 259: ! 260: if (!TCCopyFile (inputFile, outputFile)) ! 261: { ! 262: handleWin32Error (hwndDlg); ! 263: PkgError ("Cannot copy 'TrueCrypt Setup.exe' to the package"); ! 264: return FALSE; ! 265: } ! 266: ! 267: // Determine the buffer size needed for all the files and meta data and check if all required files exist ! 268: ! 269: bufLen = 0; ! 270: ! 271: for (i = 0; i < sizeof (szCompressedFiles) / sizeof (szCompressedFiles[0]); i++) ! 272: { ! 273: _snprintf (szTmpFilePath, sizeof(szTmpFilePath), "%s%s", szDestDir, szCompressedFiles[i]); ! 274: ! 275: if (!FileExists (szTmpFilePath)) ! 276: { ! 277: char tmpstr [1000]; ! 278: ! 279: _snprintf (tmpstr, sizeof(tmpstr), "File not found:\n\n'%s'", szTmpFilePath); ! 280: remove (outputFile); ! 281: PkgError (tmpstr); ! 282: return FALSE; ! 283: } ! 284: ! 285: bufLen += (int) GetFileSize64 (szTmpFilePath); ! 286: ! 287: bufLen += 2; // 16-bit filename length ! 288: bufLen += strlen(szCompressedFiles[i]); // Filename ! 289: bufLen += 4; // CRC-32 ! 290: bufLen += 4; // 32-bit file length ! 291: } ! 292: ! 293: buffer = malloc (bufLen + 524288); // + 512K reserve ! 294: if (buffer == NULL) ! 295: { ! 296: PkgError ("Cannot allocate memory for uncompressed data"); ! 297: remove (outputFile); ! 298: return FALSE; ! 299: } ! 300: ! 301: ! 302: // Write the start marker ! 303: if (!SaveBufferToFile (MAG_START_MARKER, outputFile, strlen (MAG_START_MARKER), TRUE)) ! 304: { ! 305: PkgError ("Cannot write the start marker"); ! 306: remove (outputFile); ! 307: return FALSE; ! 308: } ! 309: ! 310: ! 311: bufIndex = buffer; ! 312: ! 313: // Copy all required files and their meta data to the buffer ! 314: for (i = 0; i < sizeof (szCompressedFiles) / sizeof (szCompressedFiles[0]); i++) ! 315: { ! 316: DWORD tmpFileSize; ! 317: unsigned char *tmpBuffer; ! 318: ! 319: _snprintf (szTmpFilePath, sizeof(szTmpFilePath), "%s%s", szDestDir, szCompressedFiles[i]); ! 320: ! 321: tmpBuffer = LoadFile (szTmpFilePath, &tmpFileSize); ! 322: ! 323: if (tmpBuffer == NULL) ! 324: { ! 325: char tmpstr [1000]; ! 326: ! 327: free (tmpBuffer); ! 328: _snprintf (tmpstr, sizeof(tmpstr), "Cannot load file \n'%s'", szTmpFilePath); ! 329: remove (outputFile); ! 330: PkgError (tmpstr); ! 331: goto msep_err; ! 332: } ! 333: ! 334: // Copy the filename length to the main buffer ! 335: mputWord (bufIndex, (WORD) strlen(szCompressedFiles[i])); ! 336: ! 337: // Copy the filename to the main buffer ! 338: memcpy (bufIndex, szCompressedFiles[i], strlen(szCompressedFiles[i])); ! 339: bufIndex += strlen(szCompressedFiles[i]); ! 340: ! 341: // Compute CRC-32 hash of the uncompressed file and copy it to the main buffer ! 342: mputLong (bufIndex, GetCrc32 (tmpBuffer, tmpFileSize)); ! 343: ! 344: // Copy the file length to the main buffer ! 345: mputLong (bufIndex, (unsigned __int32) tmpFileSize); ! 346: ! 347: // Copy the file contents to the main buffer ! 348: memcpy (bufIndex, tmpBuffer, tmpFileSize); ! 349: bufIndex += tmpFileSize; ! 350: ! 351: free (tmpBuffer); ! 352: } ! 353: ! 354: // Calculate the total size of the uncompressed data ! 355: uncompressedDataLen = (int) (bufIndex - buffer); ! 356: ! 357: // Write total size of the uncompressed data ! 358: szTmp32bitPtr = szTmp32bit; ! 359: mputLong (szTmp32bitPtr, (unsigned __int32) uncompressedDataLen); ! 360: if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE)) ! 361: { ! 362: remove (outputFile); ! 363: PkgError ("Cannot write the total size of the uncompressed data"); ! 364: return FALSE; ! 365: } ! 366: ! 367: // Compress all the files and meta data in the buffer to create a solid archive ! 368: ! 369: compressedBuffer = malloc (uncompressedDataLen + 524288); // + 512K reserve ! 370: if (compressedBuffer == NULL) ! 371: { ! 372: remove (outputFile); ! 373: PkgError ("Cannot allocate memory for compressed data"); ! 374: return FALSE; ! 375: } ! 376: ! 377: compressedDataLen = CompressBuffer (compressedBuffer, buffer, uncompressedDataLen); ! 378: if (compressedDataLen <= 0) ! 379: { ! 380: remove (outputFile); ! 381: PkgError ("Failed to compress the data"); ! 382: return FALSE; ! 383: } ! 384: ! 385: free (buffer); ! 386: ! 387: // Write the total size of the compressed data ! 388: szTmp32bitPtr = szTmp32bit; ! 389: mputLong (szTmp32bitPtr, (unsigned __int32) compressedDataLen); ! 390: if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE)) ! 391: { ! 392: remove (outputFile); ! 393: PkgError ("Cannot write the total size of the compressed data"); ! 394: return FALSE; ! 395: } ! 396: ! 397: // Write the compressed data ! 398: if (!SaveBufferToFile (compressedBuffer, outputFile, compressedDataLen, TRUE)) ! 399: { ! 400: remove (outputFile); ! 401: PkgError ("Cannot write compressed data to the package"); ! 402: return FALSE; ! 403: } ! 404: ! 405: // Write the end marker ! 406: if (!SaveBufferToFile (MagEndMarker, outputFile, strlen (MagEndMarker), TRUE)) ! 407: { ! 408: remove (outputFile); ! 409: PkgError ("Cannot write the end marker"); ! 410: return FALSE; ! 411: } ! 412: ! 413: free (compressedBuffer); ! 414: ! 415: // Compute and write CRC-32 hash of the entire package ! 416: { ! 417: DWORD tmpFileSize; ! 418: char *tmpBuffer; ! 419: ! 420: tmpBuffer = LoadFile (outputFile, &tmpFileSize); ! 421: ! 422: if (tmpBuffer == NULL) ! 423: { ! 424: handleWin32Error (hwndDlg); ! 425: remove (outputFile); ! 426: PkgError ("Cannot load the package to compute CRC"); ! 427: return FALSE; ! 428: } ! 429: ! 430: // Zero all bytes that change when the exe is digitally signed (except appended blocks). ! 431: WipeSignatureAreas (tmpBuffer); ! 432: ! 433: szTmp32bitPtr = szTmp32bit; ! 434: mputLong (szTmp32bitPtr, GetCrc32 (tmpBuffer, tmpFileSize)); ! 435: if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE)) ! 436: { ! 437: remove (outputFile); ! 438: PkgError ("Cannot write the total size of the compressed data"); ! 439: return FALSE; ! 440: } ! 441: ! 442: free (tmpBuffer); ! 443: } ! 444: ! 445: sprintf (tmpStr, "Self-extracting package successfully created (%s)", outputFile); ! 446: PkgInfo (tmpStr); ! 447: return TRUE; ! 448: ! 449: msep_err: ! 450: free (buffer); ! 451: free (compressedBuffer); ! 452: return FALSE; ! 453: } ! 454: ! 455: ! 456: // Verifies the CRC-32 of the whole self-extracting package (except the digital signature areas, if present) ! 457: BOOL VerifyPackageIntegrity (void) ! 458: { ! 459: int fileDataEndPos = 0; ! 460: int fileDataStartPos = 0; ! 461: unsigned __int32 crc = 0; ! 462: unsigned char *tmpBuffer; ! 463: int tmpFileSize; ! 464: char path [TC_MAX_PATH]; ! 465: ! 466: GetModuleFileName (NULL, path, sizeof (path)); ! 467: ! 468: fileDataEndPos = (int) FindStringInFile (path, MagEndMarker, strlen (MagEndMarker)); ! 469: if (fileDataEndPos < 0) ! 470: { ! 471: Error ("DIST_PACKAGE_CORRUPTED"); ! 472: return FALSE; ! 473: } ! 474: fileDataEndPos--; ! 475: ! 476: fileDataStartPos = (int) FindStringInFile (path, MAG_START_MARKER, strlen (MAG_START_MARKER)); ! 477: if (fileDataStartPos < 0) ! 478: { ! 479: Error ("DIST_PACKAGE_CORRUPTED"); ! 480: return FALSE; ! 481: } ! 482: fileDataStartPos += strlen (MAG_START_MARKER); ! 483: ! 484: ! 485: if (!LoadInt32 (path, &crc, fileDataEndPos + strlen (MagEndMarker) + 1)) ! 486: { ! 487: Error ("CANT_VERIFY_PACKAGE_INTEGRITY"); ! 488: return FALSE; ! 489: } ! 490: ! 491: // Compute the CRC-32 hash of the whole file (except the digital signature area, if present) ! 492: tmpBuffer = LoadFile (path, &tmpFileSize); ! 493: ! 494: if (tmpBuffer == NULL) ! 495: { ! 496: Error ("CANT_VERIFY_PACKAGE_INTEGRITY"); ! 497: return FALSE; ! 498: } ! 499: ! 500: // Zero all bytes that change when an exe is digitally signed (except appended blocks). ! 501: WipeSignatureAreas (tmpBuffer); ! 502: ! 503: if (crc != GetCrc32 (tmpBuffer, fileDataEndPos + 1 + strlen (MagEndMarker))) ! 504: { ! 505: free (tmpBuffer); ! 506: Error ("DIST_PACKAGE_CORRUPTED"); ! 507: return FALSE; ! 508: } ! 509: ! 510: free (tmpBuffer); ! 511: ! 512: return TRUE; ! 513: } ! 514: ! 515: ! 516: // Determines whether we are a self-extracting package ! 517: BOOL IsSelfExtractingPackage (void) ! 518: { ! 519: char path [TC_MAX_PATH]; ! 520: ! 521: GetModuleFileName (NULL, path, sizeof (path)); ! 522: ! 523: return (FindStringInFile (path, MagEndMarker, strlen (MagEndMarker)) != -1); ! 524: } ! 525: ! 526: ! 527: static void FreeAllFileBuffers (void) ! 528: { ! 529: int fileNo; ! 530: ! 531: if (DecompressedData != NULL) ! 532: { ! 533: free (DecompressedData); ! 534: DecompressedData = NULL; ! 535: } ! 536: ! 537: for (fileNo = 0; fileNo < NBR_COMPRESSED_FILES; fileNo++) ! 538: { ! 539: Decompressed_Files[fileNo].fileName = NULL; ! 540: Decompressed_Files[fileNo].fileContent = NULL; ! 541: Decompressed_Files[fileNo].fileNameLength = 0; ! 542: Decompressed_Files[fileNo].fileLength = 0; ! 543: Decompressed_Files[fileNo].crc = 0; ! 544: } ! 545: } ! 546: ! 547: ! 548: // Assumes that VerifyPackageIntegrity() has been used. Returns TRUE, if successful (otherwise FALSE). ! 549: // Creates a table of pointers to buffers containing the following objects for each file: ! 550: // filename size, filename (not null-terminated!), file size, file CRC-32, uncompressed file contents. ! 551: // For details, see the definition of the DECOMPRESSED_FILE structure. ! 552: BOOL SelfExtractInMemory (char *path) ! 553: { ! 554: int filePos = 0, fileNo = 0; ! 555: int fileDataEndPos = 0; ! 556: int fileDataStartPos = 0; ! 557: unsigned int uncompressedLen = 0; ! 558: unsigned int compressedLen = 0; ! 559: unsigned char *compressedData = NULL; ! 560: unsigned char *bufPos = NULL, *bufEndPos = NULL; ! 561: ! 562: FreeAllFileBuffers(); ! 563: ! 564: fileDataEndPos = (int) FindStringInFile (path, MagEndMarker, strlen (MagEndMarker)); ! 565: if (fileDataEndPos < 0) ! 566: { ! 567: Error ("CANNOT_READ_FROM_PACKAGE"); ! 568: return FALSE; ! 569: } ! 570: ! 571: fileDataEndPos--; ! 572: ! 573: fileDataStartPos = (int) FindStringInFile (path, MAG_START_MARKER, strlen (MAG_START_MARKER)); ! 574: if (fileDataStartPos < 0) ! 575: { ! 576: Error ("CANNOT_READ_FROM_PACKAGE"); ! 577: return FALSE; ! 578: } ! 579: ! 580: fileDataStartPos += strlen (MAG_START_MARKER); ! 581: ! 582: filePos = fileDataStartPos; ! 583: ! 584: // Read the stored total size of the uncompressed data ! 585: if (!LoadInt32 (path, &uncompressedLen, filePos)) ! 586: { ! 587: Error ("CANNOT_READ_FROM_PACKAGE"); ! 588: return FALSE; ! 589: } ! 590: ! 591: filePos += 4; ! 592: ! 593: // Read the stored total size of the compressed data ! 594: if (!LoadInt32 (path, &compressedLen, filePos)) ! 595: { ! 596: Error ("CANNOT_READ_FROM_PACKAGE"); ! 597: return FALSE; ! 598: } ! 599: ! 600: filePos += 4; ! 601: ! 602: if (compressedLen != fileDataEndPos - fileDataStartPos - 8 + 1) ! 603: { ! 604: Error ("DIST_PACKAGE_CORRUPTED"); ! 605: } ! 606: ! 607: DecompressedData = malloc (uncompressedLen + 524288); // + 512K reserve ! 608: if (DecompressedData == NULL) ! 609: { ! 610: Error ("ERR_MEM_ALLOC"); ! 611: return FALSE; ! 612: } ! 613: ! 614: bufPos = DecompressedData; ! 615: bufEndPos = bufPos + uncompressedLen - 1; ! 616: ! 617: compressedData = LoadFileBlock (path, filePos, compressedLen); ! 618: ! 619: if (compressedData == NULL) ! 620: { ! 621: free (DecompressedData); ! 622: DecompressedData = NULL; ! 623: ! 624: Error ("CANNOT_READ_FROM_PACKAGE"); ! 625: return FALSE; ! 626: } ! 627: ! 628: // Decompress the data ! 629: if (DecompressBuffer (DecompressedData, compressedData, compressedLen) != uncompressedLen) ! 630: { ! 631: Error ("DIST_PACKAGE_CORRUPTED"); ! 632: goto sem_end; ! 633: } ! 634: ! 635: while (bufPos <= bufEndPos && fileNo < NBR_COMPRESSED_FILES) ! 636: { ! 637: // Filename length ! 638: Decompressed_Files[fileNo].fileNameLength = mgetWord (bufPos); ! 639: ! 640: // Filename ! 641: Decompressed_Files[fileNo].fileName = bufPos; ! 642: bufPos += Decompressed_Files[fileNo].fileNameLength; ! 643: ! 644: // CRC-32 of the file ! 645: Decompressed_Files[fileNo].crc = mgetLong (bufPos); ! 646: ! 647: // File length ! 648: Decompressed_Files[fileNo].fileLength = mgetLong (bufPos); ! 649: ! 650: // File content ! 651: Decompressed_Files[fileNo].fileContent = bufPos; ! 652: bufPos += Decompressed_Files[fileNo].fileLength; ! 653: ! 654: // Verify CRC-32 of the file (to verify that it didn't get corrupted while creating the solid archive). ! 655: if (Decompressed_Files[fileNo].crc ! 656: != GetCrc32 (Decompressed_Files[fileNo].fileContent, Decompressed_Files[fileNo].fileLength)) ! 657: { ! 658: Error ("DIST_PACKAGE_CORRUPTED"); ! 659: goto sem_end; ! 660: } ! 661: ! 662: fileNo++; ! 663: } ! 664: ! 665: if (fileNo < NBR_COMPRESSED_FILES) ! 666: { ! 667: Error ("DIST_PACKAGE_CORRUPTED"); ! 668: goto sem_end; ! 669: } ! 670: ! 671: free (compressedData); ! 672: return TRUE; ! 673: ! 674: sem_end: ! 675: FreeAllFileBuffers(); ! 676: free (compressedData); ! 677: return FALSE; ! 678: } ! 679: ! 680: ! 681: void __cdecl ExtractAllFilesThread (void *hwndDlg) ! 682: { ! 683: int fileNo; ! 684: BOOL bSuccess = FALSE; ! 685: char packageFile [TC_MAX_PATH]; ! 686: ! 687: InvalidateRect (GetDlgItem (GetParent (hwndDlg), IDD_INSTL_DLG), NULL, TRUE); ! 688: ! 689: ClearLogWindow (hwndDlg); ! 690: ! 691: GetModuleFileName (NULL, packageFile, sizeof (packageFile)); ! 692: ! 693: if (!(bSuccess = SelfExtractInMemory (packageFile))) ! 694: goto eaf_end; ! 695: ! 696: if (mkfulldir (DestExtractPath, TRUE) != 0) ! 697: { ! 698: if (mkfulldir (DestExtractPath, FALSE) != 0) ! 699: { ! 700: wchar_t szTmp[TC_MAX_PATH]; ! 701: ! 702: handleWin32Error (hwndDlg); ! 703: wsprintfW (szTmp, GetString ("CANT_CREATE_FOLDER"), DestExtractPath); ! 704: MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_ICONHAND); ! 705: bSuccess = FALSE; ! 706: goto eaf_end; ! 707: } ! 708: } ! 709: ! 710: for (fileNo = 0; fileNo < NBR_COMPRESSED_FILES; fileNo++) ! 711: { ! 712: char fileName [TC_MAX_PATH] = {0}; ! 713: char filePath [TC_MAX_PATH] = {0}; ! 714: ! 715: // Filename ! 716: strncpy (fileName, Decompressed_Files[fileNo].fileName, Decompressed_Files[fileNo].fileNameLength); ! 717: fileName [Decompressed_Files[fileNo].fileNameLength] = 0; ! 718: strcpy (filePath, DestExtractPath); ! 719: strcat (filePath, fileName); ! 720: ! 721: StatusMessageParam (hwndDlg, "EXTRACTING_VERB", filePath); ! 722: ! 723: // Write the file ! 724: if (!SaveBufferToFile ( ! 725: Decompressed_Files[fileNo].fileContent, ! 726: filePath, ! 727: Decompressed_Files[fileNo].fileLength, ! 728: FALSE)) ! 729: { ! 730: wchar_t szTmp[512]; ! 731: ! 732: _snwprintf (szTmp, sizeof (szTmp) / 2, GetString ("CANNOT_WRITE_FILE_X"), filePath); ! 733: MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); ! 734: bSuccess = FALSE; ! 735: goto eaf_end; ! 736: } ! 737: UpdateProgressBarProc ((int) (100 * ((float) fileNo / NBR_COMPRESSED_FILES))); ! 738: } ! 739: ! 740: eaf_end: ! 741: FreeAllFileBuffers(); ! 742: ! 743: if (bSuccess) ! 744: PostMessage (MainDlg, TC_APPMSG_EXTRACTION_SUCCESS, 0, 0); ! 745: else ! 746: PostMessage (MainDlg, TC_APPMSG_EXTRACTION_FAILURE, 0, 0); ! 747: } ! 748:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.