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 | |