Oops, I must have hit the wrong reply button.
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).
That was worded poorly, Copy/Move already handle copying file attributes and I imagine would eventually implement copying the access control list information. Implementing ReplaceFile as calls to either Copy or Move takes these issues into account.
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? From my perspective the "remarks" section discusses the implementation of
ReplaceFile as calls to existing API functions (as a sort of macro) as a convenience. Granted, it discusses moving files instead of copying but that conflicted with the file locking.
Should I make a new patch file with the previously attached changes or would you prefer that the function be implemented in the read/write manner? Re-implementing the function in such a fashion would make it possible to do a more move-like operation while maintaining the file locking, but would lose out on any future improvements to CopyFile.
Erich Hoover ehoover@mines.edu
On 2/28/07, Felix Nawothnig flexo@holycrap.org wrote:
(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; }