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