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