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