1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
24 #pragma warning(disable:4740)
25 #endif
26
27 #define _WIN32_WINNT 0x0400
28 #include "macros.h"
29
30 #define BUFSIZE 16384
31
DefCopyProgressRoutine(LARGE_INTEGER TotalFileSize,LARGE_INTEGER TotalBytesTransferred,LARGE_INTEGER StreamSize,LARGE_INTEGER StreamBytesTransferred,DWORD dwStreamNumber,DWORD dwCallbackReason,HANDLE hSourceFile,HANDLE hDestinationFile,LPVOID lpData)32 static DWORD CALLBACK DefCopyProgressRoutine(
33 LARGE_INTEGER TotalFileSize, // total file size, in bytes
34 LARGE_INTEGER TotalBytesTransferred,
35 // total number of bytes transferred
36 LARGE_INTEGER StreamSize, // total number of bytes for this stream
37 LARGE_INTEGER StreamBytesTransferred,
38 // total number of bytes transferred for
39 // this stream
40 DWORD dwStreamNumber, // the current stream
41 DWORD dwCallbackReason, // reason for callback
42 HANDLE hSourceFile, // handle to the source file
43 HANDLE hDestinationFile, // handle to the destination file
44 LPVOID lpData // passed by CopyFileEx
45 )
46 {
47 return PROGRESS_CONTINUE;
48 }
49
50
51 IMPLEMENT_THUNK( kernel32, WINDOWS, BOOL, WINAPI, CopyFileExA, ( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, LPPROGRESS_ROUTINE lpProgressRoutine, LPVOID lpData, LPBOOL pbCancel, DWORD dwCopyFlags ) )
52 {
53 BOOL fSuccess = FALSE; // Assume failure
54
55 HANDLE hSourceFile = CreateFileA(
56 lpExistingFileNameA,
57 GENERIC_READ,
58 FILE_SHARE_READ | FILE_SHARE_WRITE,
59 NULL,
60 OPEN_EXISTING,
61 0,
62 NULL
63 );
64
65 if ( IsValidHandle(hSourceFile) )
66 {
67 LARGE_INTEGER FileSize, BytesTransferred;
68 HANDLE hTargetFile = NULL;
69
70 SetLastError( ERROR_SUCCESS );
71 FileSize.LowPart = GetFileSize( hSourceFile, (LPDWORD)&FileSize.HighPart );
72 BytesTransferred.QuadPart = 0;
73
74 if ( (DWORD)-1 != FileSize.LowPart || ERROR_SUCCESS == GetLastError() )
75 hTargetFile = CreateFileA(
76 lpNewFileNameA,
77 GENERIC_WRITE,
78 0,
79 NULL,
80 (DWORD) ((dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ? CREATE_NEW : CREATE_ALWAYS),
81 0,
82 NULL
83 );
84
85 if ( IsValidHandle(hTargetFile) )
86 {
87 DWORD dwProgressResult = PROGRESS_CONTINUE;
88
89 fSuccess = SetEndOfFile( hTargetFile );
90
91 if ( fSuccess )
92 {
93 if ( !lpProgressRoutine )
94 lpProgressRoutine = DefCopyProgressRoutine;
95
96 dwProgressResult = lpProgressRoutine(
97 FileSize,
98 BytesTransferred,
99 FileSize,
100 BytesTransferred,
101 1,
102 CALLBACK_STREAM_SWITCH,
103 hSourceFile,
104 hTargetFile,
105 lpData
106 );
107
108 // Suppress further notifications
109
110 if ( PROGRESS_QUIET == dwProgressResult )
111 {
112 lpProgressRoutine = DefCopyProgressRoutine;
113 dwProgressResult = PROGRESS_CONTINUE;
114 }
115 }
116
117 while ( fSuccess && PROGRESS_CONTINUE == dwProgressResult )
118 {
119 BYTE buffer[BUFSIZE];
120 DWORD dwBytesRead, dwBytesWritten = 0;
121
122 fSuccess = ReadFile( hSourceFile, buffer, BUFSIZE, &dwBytesRead, NULL );
123
124 if ( !dwBytesRead ) break;
125
126 if ( fSuccess )
127 fSuccess = WriteFile( hTargetFile, buffer, dwBytesRead, &dwBytesWritten, NULL );
128
129 if ( fSuccess )
130 {
131 BytesTransferred.QuadPart += (LONGLONG)dwBytesWritten;
132
133 if ( pbCancel && *pbCancel )
134 dwProgressResult = PROGRESS_CANCEL;
135 else
136 dwProgressResult = lpProgressRoutine(
137 FileSize,
138 BytesTransferred,
139 FileSize,
140 BytesTransferred,
141 1,
142 CALLBACK_CHUNK_FINISHED,
143 hSourceFile,
144 hTargetFile,
145 lpData
146 );
147
148 }
149
150 }
151
152 CloseHandle( hTargetFile );
153
154 if ( PROGRESS_CANCEL == dwProgressResult )
155 DeleteFileA( lpNewFileNameA );
156 }
157
158
159 CloseHandle( hSourceFile );
160 }
161
162 return fSuccess;
163 }