windows-nt/Source/XPSP1/NT/admin/pchealth/helpctr/service/common/utils.cpp
2020-09-26 16:20:57 +08:00

484 lines
12 KiB
C++

/******************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name:
utils.cpp
Abstract:
This file contains the implementation of various utility functions.
Revision History:
Davide Massarenti (Dmassare) 03/14/2000
created
******************************************************************************/
#include "stdafx.h"
////////////////////////////////////////////////////////////////////////////////
static const WCHAR c_szDataFiles_Pattern[] = L"pchdt_*.ca?";
////////////////////////////////////////////////////////////////////////////////
HRESULT SVC::OpenStreamForRead( /*[in]*/ LPCWSTR szFile ,
/*[out]*/ IStream* *pVal ,
/*[in]*/ bool fDeleteOnRelease )
{
__HCP_FUNC_ENTRY( "SVC::OpenStreamForRead" );
HRESULT hr;
CComPtr<MPC::FileStream> stream;
MPC::wstring strFileFull;
__MPC_PARAMCHECK_BEGIN(hr)
__MPC_PARAMCHECK_STRING_NOT_EMPTY(szFile);
__MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
__MPC_PARAMCHECK_END();
MPC::SubstituteEnvVariables( strFileFull = szFile );
//
// Create a stream for a file.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &stream ));
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->InitForRead ( strFileFull.c_str() ));
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->DeleteOnRelease( fDeleteOnRelease ));
//
// Return the stream to the caller.
//
*pVal = stream.Detach();
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT SVC::OpenStreamForWrite( /*[in]*/ LPCWSTR szFile ,
/*[out]*/ IStream* *pVal ,
/*[in]*/ bool fDeleteOnRelease )
{
__HCP_FUNC_ENTRY( "SVC::OpenStreamForWrite" );
HRESULT hr;
CComPtr<MPC::FileStream> stream;
MPC::wstring strFileFull;
__MPC_PARAMCHECK_BEGIN(hr)
__MPC_PARAMCHECK_STRING_NOT_EMPTY(szFile);
__MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
__MPC_PARAMCHECK_END();
MPC::SubstituteEnvVariables( strFileFull = szFile );
//
// Create a stream for a file.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &stream ));
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->InitForWrite ( strFileFull.c_str() ));
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->DeleteOnRelease( fDeleteOnRelease ));
//
// Return the stream to the caller.
//
*pVal = stream.Detach();
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////////////////////////////////////////////
HRESULT SVC::CopyFileWhileImpersonating( /*[in]*/ LPCWSTR szSrc ,
/*[in]*/ LPCWSTR szDst ,
/*[in]*/ MPC::Impersonation& imp ,
/*[in]*/ bool fImpersonateForSource )
{
__HCP_FUNC_ENTRY( "SVC::CopyFileWhileImpersonating" );
HRESULT hr;
CComPtr<IStream> streamSrc;
CComPtr<IStream> streamDst;
if(fImpersonateForSource == true) __MPC_EXIT_IF_METHOD_FAILS(hr, imp.Impersonate());
__MPC_EXIT_IF_METHOD_FAILS(hr, SVC::OpenStreamForRead( szSrc, &streamSrc ));
if(fImpersonateForSource == true) __MPC_EXIT_IF_METHOD_FAILS(hr, imp.RevertToSelf());
////////////////////
if(fImpersonateForSource == false) __MPC_EXIT_IF_METHOD_FAILS(hr, imp.Impersonate());
__MPC_EXIT_IF_METHOD_FAILS(hr, SVC::OpenStreamForWrite( szDst, &streamDst ));
if(fImpersonateForSource == false) __MPC_EXIT_IF_METHOD_FAILS(hr, imp.RevertToSelf());
////////////////////
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::BaseStream::TransferData( streamSrc, streamDst ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
(void)imp.RevertToSelf();
__HCP_FUNC_EXIT(hr);
}
HRESULT SVC::CopyOrExtractFileWhileImpersonating( /*[in]*/ LPCWSTR szSrc ,
/*[in]*/ LPCWSTR szDst ,
/*[in]*/ MPC::Impersonation& imp )
{
__HCP_FUNC_ENTRY( "SVC::CopyOrExtractFileWhileImpersonating" );
HRESULT hr;
MPC::wstring strTempFile;
//
// First of all, try to simply copy the file.
//
if(FAILED(hr = CopyFileWhileImpersonating( szSrc, szDst, imp )))
{
int iLen = wcslen( szSrc );
if(hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || iLen < 1)
{
__MPC_FUNC_LEAVE;
}
else
{
MPC::wstring strSrc2( szSrc ); strSrc2[iLen-1] = '_';
LPCWSTR szSrc3;
//
// Simple copy failed, let's try to copy the same file, with the last character changed to an underscore.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetTemporaryFileName( strTempFile ));
__MPC_EXIT_IF_METHOD_FAILS(hr, CopyFileWhileImpersonating( strSrc2.c_str(), strTempFile.c_str(), imp ));
//
// Success, so it should be a cabinet, extract the real file.
//
szSrc3 = wcsrchr( szSrc, '\\' );
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::DecompressFromCabinet( strTempFile.c_str(), szDst, szSrc3 ? szSrc3+1 : szSrc ));
}
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
(void)MPC::RemoveTemporaryFile( strTempFile );
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////////////////////////////////////////////
HRESULT SVC::LocateDataArchive( /*[in ]*/ LPCWSTR szDir ,
/*[out]*/ MPC::WStringList& lst )
{
__HCP_FUNC_ENTRY( "SVC::LocateDataArchive" );
HRESULT hr;
MPC::wstring strName;
MPC::wstring strInput( szDir ); MPC::SubstituteEnvVariables( strInput );
MPC::FileSystemObject fso ( strInput.c_str() );
MPC::FileSystemObject::List fso_lst;
MPC::FileSystemObject::IterConst fso_it;
//
// Locate the "pchdt_<XX>.ca?" file.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, fso.Scan( false, true, c_szDataFiles_Pattern ));
__MPC_EXIT_IF_METHOD_FAILS(hr, fso.EnumerateFiles( fso_lst ));
for(fso_it=fso_lst.begin(); fso_it != fso_lst.end(); fso_it++)
{
MPC::wstring& strDataArchive = *(lst.insert( lst.end() ));
int iLen;
__MPC_EXIT_IF_METHOD_FAILS(hr, (*fso_it)->get_Path( strDataArchive ));
//
// If it's a compressed file from the CD, return the real name.
//
iLen = strDataArchive.size();
if(iLen && strDataArchive[iLen-1] == '_')
{
strDataArchive[iLen-1] = 'b';
}
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
////////////////////////////////////////////////////////////////////////////////
HRESULT SVC::RemoveAndRecreateDirectory( /*[in]*/ const MPC::wstring& strDir, /*[in]*/ LPCWSTR szExtra, /*[in]*/ bool fRemove, /*[in]*/ bool fRecreate )
{
return RemoveAndRecreateDirectory( strDir.c_str(), szExtra, fRemove, fRecreate );
}
HRESULT SVC::RemoveAndRecreateDirectory( /*[in]*/ LPCWSTR szDir, /*[in]*/ LPCWSTR szExtra, /*[in]*/ bool fRemove, /*[in]*/ bool fRecreate )
{
HRESULT hr;
MPC::wstring strPath( szDir ); if(szExtra) strPath.append( szExtra );
if(SUCCEEDED(hr = MPC::SubstituteEnvVariables( strPath )))
{
MPC::FileSystemObject fso( strPath.c_str() );
if(fRemove)
{
hr = fso.Delete( true, false );
}
if(SUCCEEDED(hr))
{
if(fRecreate)
{
hr = fso.CreateDir( /*fForce*/true );
}
}
}
return hr;
}
HRESULT SVC::ChangeSD( /*[in]*/ MPC::SecurityDescriptor& sdd ,
/*[in]*/ MPC::wstring strPath ,
/*[in]*/ LPCWSTR szExtra )
{
__HCP_FUNC_ENTRY( "SVC::ChangeSD" );
HRESULT hr;
if(szExtra) strPath.append( szExtra );
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SubstituteEnvVariables( strPath ));
{
MPC::FileSystemObject fso( strPath.c_str() );
__MPC_EXIT_IF_METHOD_FAILS(hr, fso.CreateDir( true ));
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::SetFileSecurityW( strPath.c_str() ,
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION |
PROTECTED_DACL_SECURITY_INFORMATION ,
sdd.GetSD() ));
}
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr);
}
////////////////////////////////////////////////////////////////////////////////
static HRESULT local_ReadWithRetry( /*[in]*/ const MPC::wstring& strFile ,
/*[in]*/ MPC::FileStream* stream ,
/*[in]*/ DWORD dwTimeout ,
/*[in]*/ DWORD dwRetries )
{
HRESULT hr;
while(1)
{
if(SUCCEEDED(hr = stream->InitForRead( strFile.c_str() ))) return S_OK;
if(hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED ) ||
hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) ||
hr == HRESULT_FROM_WIN32(ERROR_LOCK_VIOLATION ) )
{
(void)stream->Close();
if(dwRetries)
{
::Sleep( dwTimeout );
dwRetries--;
continue;
}
}
break;
}
return hr;
}
static HRESULT local_WriteWithRetry( /*[in]*/ const MPC::wstring& strFile ,
/*[in]*/ MPC::FileStream* stream ,
/*[in]*/ DWORD dwTimeout ,
/*[in]*/ DWORD dwRetries )
{
HRESULT hr;
while(1)
{
if(SUCCEEDED(hr = stream->InitForWrite( strFile.c_str() ))) return S_OK;
if(hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED ) ||
hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) ||
hr == HRESULT_FROM_WIN32(ERROR_LOCK_VIOLATION ) )
{
(void)stream->Close();
if(dwRetries)
{
::Sleep( dwTimeout );
dwRetries--;
continue;
}
}
break;
}
return hr;
}
HRESULT SVC::SafeLoad( /*[in]*/ const MPC::wstring& strFile ,
/*[in]*/ CComPtr<MPC::FileStream>& stream ,
/*[in]*/ DWORD dwTimeout ,
/*[in]*/ DWORD dwRetries )
{
__HCP_FUNC_ENTRY( "SVC::SafeLoad" );
HRESULT hr;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &stream ));
//
// If fails, try to load "<file>.orig"
//
if(FAILED(hr = local_ReadWithRetry( strFile, stream, dwTimeout, dwRetries )))
{
MPC::wstring strFileOrig( strFile ); strFileOrig += L".orig";
__MPC_EXIT_IF_METHOD_FAILS(hr, local_ReadWithRetry( strFileOrig, stream, dwTimeout, dwRetries ));
}
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT SVC::SafeSave_Init( /*[in]*/ const MPC::wstring& strFile ,
/*[in]*/ CComPtr<MPC::FileStream>& stream ,
/*[in]*/ DWORD dwTimeout ,
/*[in]*/ DWORD dwRetries )
{
__HCP_FUNC_ENTRY( "SVC::SafeSave_Init" );
HRESULT hr;
MPC::wstring strFileNew( strFile ); strFileNew += L".new";
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir ( strFileNew ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance ( &stream ));
__MPC_EXIT_IF_METHOD_FAILS(hr, local_WriteWithRetry( strFileNew, stream, dwTimeout, dwRetries ));
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}
HRESULT SVC::SafeSave_Finalize( /*[in]*/ const MPC::wstring& strFile ,
/*[in]*/ CComPtr<MPC::FileStream>& stream ,
/*[in]*/ DWORD dwTimeout ,
/*[in]*/ DWORD dwRetries )
{
__HCP_FUNC_ENTRY( "SVC::SafeSave_Finalize" );
HRESULT hr;
MPC::wstring strFileNew ( strFile ); strFileNew += L".new";
MPC::wstring strFileOrig( strFile ); strFileOrig += L".orig";
stream.Release();
//
// Then move "<file>" to "<file>.orig"
//
(void)MPC::DeleteFile( strFileOrig );
(void)MPC::MoveFile ( strFile, strFileOrig );
while(1)
{
//
// Then rename "<file>.new" to "<file>"
//
if(SUCCEEDED(hr = MPC::MoveFile( strFileNew, strFile ))) break;
if(hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED ) ||
hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) ||
hr == HRESULT_FROM_WIN32(ERROR_LOCK_VIOLATION ) )
{
if(dwRetries)
{
::Sleep( dwTimeout );
dwRetries--;
continue;
}
}
__MPC_FUNC_LEAVE;
}
//
// Finally delete "<file>.orig"
//
(void)MPC::DeleteFile( strFileOrig );
hr = S_OK;
__HCP_FUNC_CLEANUP;
__HCP_FUNC_EXIT(hr);
}