24#include <wx/filename.h>
43#if !defined( __MINGW32__ )
67#define FileFullDirectoryInformation ( (FILE_INFORMATION_CLASS) 2 )
74#if defined( _MSC_VER ) || !defined( USE_MSYS2_FALLBACK )
77 HANDLE hFile = INVALID_HANDLE_VALUE;
78 hFile = CreateFileW( aPath.wc_str(),
83 FILE_FLAG_SEQUENTIAL_SCAN,
86 if (hFile == INVALID_HANDLE_VALUE)
91 int fd = _open_osfhandle(
reinterpret_cast<intptr_t
>( hFile ), 0 );
100 FILE* fp = _fdopen( fd, aMode.c_str() );
111 return wxFopen( aPath, aMode );
121 const SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
129 GetFileSecurityW( aSrc.wc_str(), secInfo,
nullptr, 0, &dwSize );
131 if( dwSize == 0 || GetLastError() != ERROR_INSUFFICIENT_BUFFER )
134 std::vector<BYTE> sdBuffer( dwSize );
135 PSECURITY_DESCRIPTOR pSD =
static_cast<PSECURITY_DESCRIPTOR
>( sdBuffer.data() );
137 return GetFileSecurityW( aSrc.wc_str(), secInfo, pSD, dwSize, &dwSize )
138 && SetFileSecurityW( aDest.wc_str(), secInfo, pSD );
143 DWORD attrs = GetFileAttributesW( aFilePath.wc_str() );
145 if( attrs == INVALID_FILE_ATTRIBUTES )
151 DWORD attrsToRemove = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN;
153 if( attrs & attrsToRemove )
155 attrs &= ~attrsToRemove;
156 return SetFileAttributesW( aFilePath.wc_str(), attrs ) != 0;
164 TARGET_ATTRS snapshot;
165 DWORD attrs = GetFileAttributesW( aPath.wc_str() );
167 if( attrs == INVALID_FILE_ATTRIBUTES )
173 snapshot.value =
static_cast<std::uint32_t
>( attrs )
174 & ( FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN );
175 snapshot.captured =
true;
182 if( !aAttrs.captured )
185 DWORD current = GetFileAttributesW( aPath.wc_str() );
187 if( current == INVALID_FILE_ATTRIBUTES )
190 DWORD merged = current |
static_cast<DWORD
>( aAttrs.value );
192 if( merged == current )
195 return SetFileAttributesW( aPath.wc_str(), merged ) != 0;
200 const wxString& aMode, wxString* aTempPathOut,
205 for(
unsigned attempt = 0; attempt < 32; ++attempt )
208 HANDLE h = CreateFileW( candidate.wc_str(), GENERIC_WRITE, 0,
nullptr, CREATE_NEW,
209 FILE_ATTRIBUTE_NORMAL,
nullptr );
211 if( h != INVALID_HANDLE_VALUE )
213 int fd = _open_osfhandle(
reinterpret_cast<intptr_t
>( h ), _O_WRONLY | _O_BINARY );
218 DeleteFileW( candidate.wc_str() );
222 *aError = wxString::Format( wxT(
"_open_osfhandle failed for '%s'" ),
229 FILE* fp = _wfdopen( fd, aMode.wc_str() );
234 DeleteFileW( candidate.wc_str() );
237 *aError = wxString::Format( wxT(
"_wfdopen failed for '%s'" ), candidate );
243 *aTempPathOut = candidate;
248 DWORD err = GetLastError();
250 if( err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS )
253 *aError = wxString::Format( wxT(
"CreateFile failed for '%s' (Win32 %lu)" ),
261 *aError = wxT(
"Exhausted temp-file retry budget" );
279 const DWORD attributes = GetFileAttributesW( aFileName.fn_str() );
281 return attributes != INVALID_FILE_ATTRIBUTES
282 && ( attributes & FILE_ATTRIBUTE_HIDDEN ) != 0;
292 if( aFilename.GetVolume().Length() == 1 )
294 aFilename.SetVolume(
"\\\\?\\" + aFilename.GetVolume() +
":" );
295 else if( aFilename.GetVolume().Length() > 1
296 && aFilename.GetVolume().StartsWith( wxT(
"\\\\" ) )
297 && !aFilename.GetVolume().StartsWith( wxT(
"\\\\?" ) ) )
302 aFilename.SetVolume(
"\\\\?\\UNC" + aFilename.GetVolume().Mid( 1 ) );
303 else if( aFilename.GetVolume().StartsWith( wxT(
"\\\\?" ) )
304 && aFilename.GetDirs().size() >= 2
305 && aFilename.GetDirs()[0] ==
"UNC" )
311 aFilename.SetVolume(
"\\\\?\\UNC\\" + aFilename.GetDirs()[1] );
312 aFilename.RemoveDir( 0 );
313 aFilename.RemoveDir( 0 );
320 long long timestamp = 0;
325 static PFN_NtQueryDirectoryFile pNtQueryDirectoryFile =
nullptr;
327 if( !pNtQueryDirectoryFile )
329 HMODULE ntdll = GetModuleHandleW(
L"ntdll.dll" );
333 pNtQueryDirectoryFile =
334 (PFN_NtQueryDirectoryFile) GetProcAddress( ntdll,
"NtQueryDirectoryFile" );
338 if( !pNtQueryDirectoryFile )
341 std::wstring dirPath( aDirPath.t_str() );
343 if( !dirPath.empty() && dirPath.back() !=
L'\\' )
349 if( dirPath.size() >= 2 && dirPath[0] ==
L'\\' && dirPath[1] ==
L'\\' )
351 if( dirPath.size() >= 4 && dirPath[2] ==
L'?' && dirPath[3] ==
L'\\' )
359 ntPath =
L"\\\\?\\UNC\\" + dirPath.substr( 2 );
365 ntPath =
L"\\\\?\\" + dirPath;
368 HANDLE hDir = CreateFileW( ntPath.c_str(), FILE_LIST_DIRECTORY,
369 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
370 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
nullptr );
372 if( hDir == INVALID_HANDLE_VALUE )
375 std::wstring pattern( aFilespec.t_str() );
378 alignas(
sizeof( LONGLONG ) )
char buffer[64 * 1024];
380 IO_STATUS_BLOCK iosb;
382 bool firstQuery =
true;
386 status = pNtQueryDirectoryFile( hDir,
nullptr,
nullptr,
nullptr, &iosb, buffer,
388 nullptr, firstQuery ? TRUE : FALSE );
403 && PathMatchSpecW( fileName.c_str(), pattern.c_str() ) )
428 if( std::fflush( aFp ) != 0 )
431 int fd = _fileno( aFp );
436 HANDLE h =
reinterpret_cast<HANDLE>( _get_osfhandle( fd ) );
438 if( h == INVALID_HANDLE_VALUE )
441 return FlushFileBuffers( h ) != 0;
463 for(
int attempt = 0; attempt < 10; ++attempt )
465 if( MoveFileExW( aSrc.wc_str(), aDst.wc_str(),
466 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH ) )
469 lastError = GetLastError();
471 if( lastError != ERROR_SHARING_VIOLATION && lastError != ERROR_ACCESS_DENIED
472 && lastError != ERROR_LOCK_VIOLATION )
480 if( ReplaceFileW( aDst.wc_str(), aSrc.wc_str(),
nullptr, REPLACEFILE_WRITE_THROUGH,
nullptr,
484 DWORD fallbackError = GetLastError();
488 wchar_t* msg =
nullptr;
489 FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
490 | FORMAT_MESSAGE_IGNORE_INSERTS,
491 nullptr, fallbackError ? fallbackError : lastError,
492 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
reinterpret_cast<LPWSTR
>( &msg ),
497 *aError = wxString( msg );
502 *aError = wxString::Format( wxT(
"Win32 error %lu" ), fallbackError ? fallbackError
513 m_fileHandle = CreateFileW( aFileName.wc_str(), GENERIC_READ, FILE_SHARE_READ,
514 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr );
516 if( m_fileHandle == INVALID_HANDLE_VALUE )
518 m_fileHandle =
nullptr;
519 throw std::runtime_error( std::string(
"Cannot open file: " )
520 + aFileName.ToStdString() );
523 LARGE_INTEGER fileSize;
525 if( !GetFileSizeEx( m_fileHandle, &fileSize ) )
527 CloseHandle( m_fileHandle );
528 m_fileHandle =
nullptr;
529 throw std::runtime_error( std::string(
"Cannot determine file size: " )
530 + aFileName.ToStdString() );
533 m_size =
static_cast<size_t>( fileSize.QuadPart );
537 CloseHandle( m_fileHandle );
538 m_fileHandle =
nullptr;
542 m_mapHandle = CreateFileMappingW( m_fileHandle,
nullptr, PAGE_READONLY, 0, 0,
nullptr );
546 CloseHandle( m_fileHandle );
547 m_fileHandle =
nullptr;
552 void* ptr = MapViewOfFile( m_mapHandle, FILE_MAP_READ, 0, 0, 0 );
556 CloseHandle( m_mapHandle );
557 m_mapHandle =
nullptr;
558 CloseHandle( m_fileHandle );
559 m_fileHandle =
nullptr;
564 m_data =
static_cast<const uint8_t*
>( ptr );
570 if( m_data && m_mapHandle )
571 UnmapViewOfFile( m_data );
574 CloseHandle( m_mapHandle );
577 CloseHandle( m_fileHandle );
592 auto openFile = [&]( DWORD aAccess, DWORD aDisposition )
594 return CreateFileW( aPath.wc_str(), aAccess,
595 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
596 aDisposition, FILE_ATTRIBUTE_NORMAL,
nullptr );
599 HANDLE handle = openFile( GENERIC_READ | GENERIC_WRITE, CREATE_NEW );
601 aCreated = handle != INVALID_HANDLE_VALUE;
604 handle = openFile( GENERIC_READ | GENERIC_WRITE, OPEN_EXISTING );
606 if( handle == INVALID_HANDLE_VALUE )
609 handle = openFile( GENERIC_READ, OPEN_EXISTING );
611 if( handle != INVALID_HANDLE_VALUE )
614 m_state = STATE::UNSUPPORTED;
622 OVERLAPPED overlapped = {};
625 if( LockFileEx( handle, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0,
628 m_state = STATE::HELD;
630 else if( GetLastError() == ERROR_LOCK_VIOLATION || GetLastError() == ERROR_IO_PENDING )
632 m_state = STATE::BUSY;
636 m_state = STATE::UNSUPPORTED;
647 aHeldByAnother =
false;
649 HANDLE handle = CreateFileW( aPath.wc_str(), GENERIC_READ,
650 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
651 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr );
653 if( handle == INVALID_HANDLE_VALUE )
658 OVERLAPPED overlapped = {};
662 if( LockFileEx( handle, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0,
665 UnlockFileEx( handle, 0, 1, 0, &overlapped );
667 else if( GetLastError() == ERROR_LOCK_VIOLATION || GetLastError() == ERROR_IO_PENDING )
669 aHeldByAnother =
true;
678 return m_handle !=
nullptr;
687 LARGE_INTEGER zero = {};
689 if( !SetFilePointerEx( m_handle, zero,
nullptr, FILE_BEGIN ) )
697 while( ReadFile( m_handle, buffer,
sizeof( buffer ), &read,
nullptr ) && read > 0 )
698 aContents.append( buffer, read );
709 LARGE_INTEGER zero = {};
711 if( !SetFilePointerEx( m_handle, zero,
nullptr, FILE_BEGIN ) || !SetEndOfFile( m_handle ) )
716 if( !WriteFile( m_handle, aContents.data(),
static_cast<DWORD
>( aContents.size() ), &written,
722 return written == aContents.size();
731 CloseHandle( m_handle );
735 m_state = STATE::NONE;
static constexpr DWORD LOCK_BYTE_OFFSET
typedef FILE_INFORMATION_CLASS
struct _FILE_FULL_DIR_INFORMATION FILE_FULL_DIR_INFORMATION
typedef NTSTATUS(NTAPI *PFN_NtQueryDirectoryFile)(HANDLE
struct _FILE_FULL_DIR_INFORMATION * PFILE_FULL_DIR_INFORMATION
#define FileFullDirectoryInformation