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 }