bool WinMoveFile( RString sOldPath, RString sNewPath )
{
	if( WinMoveFileInternal( DoPathReplace(sOldPath), DoPathReplace(sNewPath) ) )
		return true;
	if( GetLastError() != ERROR_ACCESS_DENIED )
		return false;
	/* Try turning off the read-only bit on the file we're overwriting. */
	SetFileAttributes( DoPathReplace(sNewPath), FILE_ATTRIBUTE_NORMAL );

	return WinMoveFileInternal( DoPathReplace(sOldPath), DoPathReplace(sNewPath) );
}
HANDLE DoFindFirstFile( const RString &sPath, WIN32_FIND_DATA *fd )
{
	return FindFirstFile( DoPathReplace(sPath), fd );
}
int DoRmdir( const RString &sPath )
{
	return rmdir( DoPathReplace(sPath) );
}
int DoRemove( const RString &sPath )
{
	return remove( DoPathReplace(sPath) );
}
int DoRename( const RString &sOldPath, const RString &sNewPath )
{
	return rename( DoPathReplace(sOldPath), DoPathReplace(sNewPath) );
}
int DoStat( const RString &sPath, struct stat *st )
{
	return stat( DoPathReplace(sPath), st );
}
int DoOpen( const RString &sPath, int flags, int perm )
{
	return open( DoPathReplace(sPath), flags, perm );
}
/* Wrappers for low-level file functions, to work around Xbox issues: */
int DoMkdir( const RString &sPath, int perm )
{
	return mkdir( DoPathReplace(sPath), perm );
}
RageFileObjDirect::~RageFileObjDirect()
{
	bool bFailed = !FinalFlush();
	
	if( m_iFD != -1 )
	{
		if( close( m_iFD ) == -1 )
		{
			WARN( ssprintf("Error closing %s: %s", this->m_sPath.c_str(), strerror(errno)) );
			SetError( strerror(errno) );
			bFailed = true;
		}
	}

	if( !(m_iMode & RageFile::WRITE) || (m_iMode & RageFile::STREAMED) )
		return;

	/* We now have path written to MakeTempFilename(m_sPath).
	 * Rename the temporary file over the real path. */

	do
	{
		if( bFailed || WriteFailed() )
			break;

		/* We now have path written to MakeTempFilename(m_sPath). Rename the
		 * temporary file over the real path. This should be an atomic operation
		 * with a journalling filesystem. That is, there should be no
		 * intermediate state a JFS might restore the file we're writing (in the
		 * case of a crash/powerdown) to an empty or partial file. */

		RString sOldPath = MakeTempFilename(m_sPath);
		RString sNewPath = m_sPath;

#if defined(WIN32)
		if( WinMoveFile(DoPathReplace(sOldPath), DoPathReplace(sNewPath)) )
			return;

		/* We failed. */
		int err = GetLastError();
		const RString error = werr_ssprintf( err, "Error renaming \"%s\" to \"%s\"", sOldPath.c_str(), sNewPath.c_str() );
		WARN( ssprintf("%s", error.c_str()) );
		SetError( error );
		break;
#else
		if( rename( sOldPath, sNewPath ) == -1 )
		{
			WARN( ssprintf("Error renaming \"%s\" to \"%s\": %s", 
					sOldPath.c_str(), sNewPath.c_str(), strerror(errno)) );
			SetError( strerror(errno) );
			break;
		}


		if( m_iMode & RageFile::SLOW_FLUSH )
		{
			RString sError;
			if( !FlushDir(Dirname(m_sPath), sError) )
			{
				WARN( ssprintf("Error synchronizing fsync(%s dir): %s", this->m_sPath.c_str(), sError.c_str()) );
				SetError( sError );
			}
		}

		// Success.
		return;
#endif
	} while(0);

	// The write or the rename failed. Delete the incomplete temporary file.
	DoRemove( MakeTempFilename(m_sPath) );
}