| 1 | // |
| 2 | // Copyright (c) Microsoft. All rights reserved. |
| 3 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
| 4 | // |
| 5 | |
| 6 | #include "standardpch.h" |
| 7 | #include "verbconcat.h" |
| 8 | #include "simpletimer.h" |
| 9 | #include "logging.h" |
| 10 | |
| 11 | #define BUFFER_SIZE 0xFFFFFF |
| 12 | |
| 13 | int verbConcat::DoWork(const char* nameOfFile1, const char* nameOfFile2) |
| 14 | { |
| 15 | SimpleTimer st1; |
| 16 | |
| 17 | LogVerbose("Concatenating '%s'+'%s' into %s" , nameOfFile1, nameOfFile2, nameOfFile1); |
| 18 | |
| 19 | LARGE_INTEGER DataTemp1; |
| 20 | LARGE_INTEGER DataTemp2; |
| 21 | |
| 22 | HANDLE hFileIn1 = CreateFileA(nameOfFile1, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, |
| 23 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); |
| 24 | if (hFileIn1 == INVALID_HANDLE_VALUE) |
| 25 | { |
| 26 | LogError("Failed to open input 1 '%s'. GetLastError()=%u" , nameOfFile1, GetLastError()); |
| 27 | return -1; |
| 28 | } |
| 29 | if (GetFileSizeEx(hFileIn1, &DataTemp1) == 0) |
| 30 | { |
| 31 | LogError("GetFileSizeEx failed. GetLastError()=%u" , GetLastError()); |
| 32 | return -1; |
| 33 | } |
| 34 | |
| 35 | LONG highDWORD = 0; |
| 36 | DWORD dwPtr = SetFilePointer(hFileIn1, 0, &highDWORD, FILE_END); |
| 37 | if (dwPtr == INVALID_SET_FILE_POINTER) |
| 38 | { |
| 39 | LogError("Failed to SetFilePointer on input 1 '%s'. GetLastError()=%u" , nameOfFile1, GetLastError()); |
| 40 | return -1; |
| 41 | } |
| 42 | |
| 43 | HANDLE hFileIn2 = CreateFileA(nameOfFile2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, |
| 44 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); |
| 45 | if (hFileIn2 == INVALID_HANDLE_VALUE) |
| 46 | { |
| 47 | LogError("Failed to open input 2 '%s'. GetLastError()=%u" , nameOfFile2, GetLastError()); |
| 48 | return -1; |
| 49 | } |
| 50 | if (GetFileSizeEx(hFileIn2, &DataTemp2) == 0) |
| 51 | { |
| 52 | LogError("2nd GetFileSizeEx failed. GetLastError()=%u" , GetLastError()); |
| 53 | return -1; |
| 54 | } |
| 55 | |
| 56 | unsigned char* buffer = new unsigned char[BUFFER_SIZE]; |
| 57 | |
| 58 | st1.Start(); |
| 59 | for (LONGLONG offset = 0; offset < DataTemp2.QuadPart; offset += BUFFER_SIZE) |
| 60 | { |
| 61 | DWORD bytesRead = -1; |
| 62 | BOOL res = ReadFile(hFileIn2, buffer, BUFFER_SIZE, &bytesRead, nullptr); |
| 63 | if (res == 0) |
| 64 | { |
| 65 | LogError("Failed to read '%s' from offset %lld. GetLastError()=%u" , nameOfFile2, offset, GetLastError()); |
| 66 | return -1; |
| 67 | } |
| 68 | DWORD bytesWritten = -1; |
| 69 | BOOL res2 = WriteFile(hFileIn1, buffer, bytesRead, &bytesWritten, nullptr); |
| 70 | if (res2 == 0) |
| 71 | { |
| 72 | LogError("Failed to write '%s' at offset %lld. GetLastError()=%u" , nameOfFile1, offset, GetLastError()); |
| 73 | return -1; |
| 74 | } |
| 75 | if (bytesRead != bytesWritten) |
| 76 | { |
| 77 | LogError("Failed to read/write matching bytes %u!=%u" , bytesRead, bytesWritten); |
| 78 | return -1; |
| 79 | } |
| 80 | } |
| 81 | st1.Stop(); |
| 82 | |
| 83 | delete[] buffer; |
| 84 | |
| 85 | if (CloseHandle(hFileIn1) == 0) |
| 86 | { |
| 87 | LogError("CloseHandle failed. GetLastError()=%u" , GetLastError()); |
| 88 | return -1; |
| 89 | } |
| 90 | if (CloseHandle(hFileIn2) == 0) |
| 91 | { |
| 92 | LogError("2nd CloseHandle failed. GetLastError()=%u" , GetLastError()); |
| 93 | return -1; |
| 94 | } |
| 95 | |
| 96 | LogInfo("Read/Wrote %lld MB @ %4.2f MB/s.\n" , DataTemp2.QuadPart / (1000 * 1000), |
| 97 | (((double)DataTemp2.QuadPart) / (1000 * 1000)) / |
| 98 | st1.GetSeconds()); // yes yes.. http://en.wikipedia.org/wiki/Megabyte_per_second#Megabyte_per_second |
| 99 | |
| 100 | return 0; |
| 101 | } |
| 102 | |