kernel32: Implement ReplaceFileA/ReplaceFileW
Erich Hoover
ehoover at mines.edu
Thu Mar 1 01:59:54 CST 2007
Skipped content of type multipart/alternative-------------- next part --------------
/**************************************************************************
* ReplaceFileW (KERNEL32.@)
* ReplaceFile (KERNEL32.@)
*/
BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName,LPCWSTR lpReplacementFileName,
LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
LPVOID lpExclude, LPVOID lpReserved)
{
BY_HANDLE_FILE_INFORMATION ifoReplaced, ifoReplacement;
HANDLE hReplaced, hReplacement, hBackup;
static const int buffer_size = 65536;
BOOL skipBackup = FALSE, ret = FALSE;
char *buffer;
DWORD count;
if (dwReplaceFlags)
FIXME("Ignoring flags %x\n", dwReplaceFlags);
/* First two arguments are mandatory */
if (!lpReplacedFileName || !lpReplacementFileName)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
/* Create a copying buffer */
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size )))
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
/*
* Open the replacement file for reading, writing, and deleting
* (writing and deleting are needed when finished)
*/
if ((hReplacement = CreateFileW(lpReplacementFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
{
goto replace_fail_1;
}
/* Obtain the file attributes from the replacement file */
if (!GetFileInformationByHandle( hReplacement, &ifoReplacement ))
{
WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(lpReplacementFileName));
goto replace_fail_2;
}
/* Open the "replaced" file for reading and writing */
if ((hReplaced = CreateFileW(lpReplacedFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
ifoReplacement.dwFileAttributes, hReplacement)) == INVALID_HANDLE_VALUE)
{
if ( GetLastError() == ERROR_FILE_NOT_FOUND )
{
/* If "replaced" does not exist then create it for the write, but skip backup */
if ((hReplaced = CreateFileW(lpReplacedFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, ifoReplacement.dwFileAttributes,
hReplacement)) == INVALID_HANDLE_VALUE)
{
goto replace_fail_2;
}
skipBackup = TRUE;
}
else
{
/* Inappropriate permissions to remove "replaced" */
SetLastError( ERROR_UNABLE_TO_REMOVE_REPLACED );
goto replace_fail_2;
}
}
/* If the user wants a backup then that needs to be performed first */
if ( lpBackupFileName && !skipBackup )
{
/* Obtain the file attributes from the "replaced" file */
if (!GetFileInformationByHandle( hReplaced, &ifoReplaced ))
{
WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(lpReplacedFileName));
goto replace_fail_3;
}
/* If an existing backup exists then copy over it */
if ((hBackup = CreateFileW(lpBackupFileName, GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, ifoReplaced.dwFileAttributes,
hReplaced)) == INVALID_HANDLE_VALUE)
{
goto replace_fail_3;
}
/* Actually copy the "replaced" file into the backup file */
while (ReadFile( hReplaced, buffer, buffer_size, &count, NULL ) && count)
{
char *p = buffer;
while (count != 0)
{
DWORD res;
if (!WriteFile( hBackup, p, count, &res, NULL ) || !res)
{
/* on failure we need to cleanup all our resources */
CloseHandle( hBackup );
goto replace_fail_3;
}
p += res;
count -= res;
}
}
/* If the file was bigger before then end it after the last new write */
SetEndOfFile( hBackup );
/* Set the filetime of the backup to that of the "replaced" file */
SetFileTime( hBackup, NULL, NULL, &ifoReplaced.ftLastWriteTime );
CloseHandle( hBackup );
/* Seek back to the beginning of the file */
SetFilePointer( hReplaced, 0, NULL, FILE_BEGIN );
}
/*
* Now that the backup has been performed (if requested), copy the replacement
* into place
*/
while (ReadFile( hReplacement, buffer, buffer_size, &count, NULL ) && count)
{
char *p = buffer;
while (count != 0)
{
DWORD res;
if (!WriteFile( hReplaced, p, count, &res, NULL ) || !res)
{
/* on failure we need to cleanup all our resources */
SetLastError( ERROR_UNABLE_TO_MOVE_REPLACEMENT);
goto replace_fail_3;
}
p += res;
count -= res;
}
}
/* If the file was bigger before then end it after the last new write */
SetEndOfFile( hReplaced );
/* Set the filetime of the "replaced" file to that of the replacement */
SetFileTime( hReplaced, NULL, NULL, &ifoReplacement.ftLastWriteTime );
/*
* Delete the replacement file, note that this delete won't really occur
* until the original handle is released.
*/
if (!DeleteFileW( lpReplacementFileName ))
{
/*
* This case should never occur, we've already checked permissions earlier
* and we are holding the file handle open.
*/
ERR("Replacement file may not be deleted!\n");
}
ret = TRUE;
/* Clean up all allocated resources */
replace_fail_3:
CloseHandle( hReplaced );
replace_fail_2:
CloseHandle( hReplacement );
replace_fail_1:
HeapFree( GetProcessHeap(), 0, buffer );
return ret;
}
More information about the wine-devel
mailing list