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