(CC-ing wine-devel again)
Erich Hoover wrote:
>> The "right" way would probably to do the copying yourself by
>> read/write.. but I dunno.
> Except that it would ignore the permissions issues that have already
> been coded into the copy routines (and any updates that may eventually
No, CreateFile (and friends) does the permissions checks (which you
would still have to call).
> be made to these routines). Also, it seems to me that MSDN is
> describing the list of function calls that ReplaceFile actually makes.
No it doesn't?
Your other objections were right. Your last version follows for wine-devel.
> ------------------------------------------------------------------------
>
> /**************************************************************************
> * ReplaceFileW (KERNEL32.@)
> * ReplaceFile (KERNEL32.@)
> */
> BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
> LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
> LPVOID lpExclude, LPVOID lpReserved)
> {
> HANDLE hReplaced, hReplacement;
> BOOL skipBackup = FALSE;
>
> if(dwReplaceFlags)
> FIXME("Ignoring flags %x\n", dwReplaceFlags);
> /* First two arguments are mandatory */
> if(!lpReplacedFileName || !lpReplacementFileName)
> {
> SetLastError( ERROR_INVALID_PARAMETER );
> return FALSE;
> }
> /*
> * Lock the "replacement" file, fail if it does not exist
> */
> if((hReplacement = CreateFileW(lpReplacementFileName, GENERIC_READ,
> FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
> NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
> {
> return FALSE;
> }
> if(!LockFile( hReplacement, 0, 0, 0, 0 ))
> {
> CloseHandle( hReplacement );
> return FALSE;
> }
> /*
> * Lock the "replaced" file while we're working.
> */
> if((hReplaced = CreateFileW(lpReplacedFileName, GENERIC_READ,
> FILE_SHARE_READ | FILE_SHARE_WRITE,
> NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
> {
> /* If "replaced" does not exist then create it for the lock, but skip backup */
> if((hReplaced = CreateFileW(lpReplacedFileName, GENERIC_READ,
> FILE_SHARE_READ | FILE_SHARE_WRITE,
> NULL, CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE)
> {
> UnlockFile( hReplacement, 0, 0, 0, 0 );
> CloseHandle( hReplacement );
> return FALSE;
> }
> skipBackup = TRUE;
> }
> if(!LockFile( hReplaced, 0, 0, 0, 0 ))
> {
> UnlockFile( hReplacement, 0, 0, 0, 0 );
> CloseHandle( hReplacement );
> CloseHandle( hReplaced );
> return FALSE;
> }
> /*
> * If the user wants a backup then that needs to be performed first
> */
> if( lpBackupFileName && !skipBackup )
> {
> /* If an existing backup exists then copy over it */
> if(!CopyFileW( lpReplacedFileName, lpBackupFileName, FALSE ))
> goto replace_fail;
> }
> /*
> * Now that the backup has been performed (if requested), copy the replacement
> * into place
> */
> if(!CopyFileW( lpReplacementFileName, lpReplacedFileName, FALSE ))
> {
> /* Assume that all access denied errors are a write problem. */
> if(GetLastError() == ERROR_ACCESS_DENIED)
> SetLastError( ERROR_UNABLE_TO_REMOVE_REPLACED );
> else
> SetLastError( ERROR_UNABLE_TO_MOVE_REPLACEMENT );
> goto replace_fail;
> }
> /* Delete the replacement file */
> if(!DeleteFileW( lpReplacementFileName ))
> return FALSE;
> /* Unlock the handles */
> UnlockFile( hReplacement, 0, 0, 0, 0 );
> CloseHandle( hReplacement );
> UnlockFile( hReplaced, 0, 0, 0, 0 );
> CloseHandle( hReplaced );
> /* All done, file replacement successful */
> return TRUE;
>
> replace_fail:
> UnlockFile( hReplacement, 0, 0, 0, 0 );
> CloseHandle( hReplacement );
> UnlockFile( hReplaced, 0, 0, 0, 0 );
> CloseHandle( hReplaced );
> return FALSE;
> }