You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
667 lines
25 KiB
667 lines
25 KiB
#include "stdinc.h"
|
|
#include "macros.h"
|
|
|
|
#include "util.h"
|
|
#include "fusionbuffer.h"
|
|
#include "fusionhandle.h"
|
|
#include "idp.h"
|
|
#include "sxsid.h"
|
|
#include "sxsutil.h"
|
|
|
|
#undef FUSION_DEBUG_HEAP
|
|
|
|
#define ULONG_STRING_LENGTH 8
|
|
#define ULONG_STRING_FORMAT L"%08lx"
|
|
#define MANIFEST_ROOT_DIRECTORY_NAME L"Manifests"
|
|
#define POLICY_ROOT_DIRECTORY_NAME L"Policies"
|
|
#define ASSEMBLY_LONGEST_MANIFEST_FILE_NAME_SUFFIX L".Manifest"
|
|
#define ASSEMBLY_POLICY_FILE_NAME_SUFFIX L".Policy"
|
|
#define ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX L".Manifest"
|
|
|
|
#define ASSEMBLY_TYPE_WIN32 L"win32"
|
|
#define ASSEMBLY_TYPE_WIN32_CCH (NUMBER_OF(ASSEMBLY_TYPE_WIN32) - 1)
|
|
|
|
#define ASSEMBLY_TYPE_WIN32_POLICY L"win32-policy"
|
|
#define ASSEMBLY_TYPE_WIN32_POLICY_CCH (NUMBER_OF(ASSEMBLY_TYPE_WIN32_POLICY) - 1)
|
|
//
|
|
// functions copied from sxs.dll
|
|
//
|
|
//
|
|
|
|
extern BOOL
|
|
SxspGetAssemblyIdentityAttributeValue(
|
|
DWORD Flags,
|
|
PCASSEMBLY_IDENTITY AssemblyIdentity,
|
|
PCSXS_ASSEMBLY_IDENTITY_ATTRIBUTE_REFERENCE AttributeReference,
|
|
OUT PCWSTR *StringOut,
|
|
OUT SIZE_T *CchOut OPTIONAL
|
|
);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// function about delete a non-empty directory recursively
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
static VOID
|
|
SxspDeleteDirectoryHelper(
|
|
CStringBuffer &dir,
|
|
WIN32_FIND_DATAW &wfd,
|
|
DWORD &dwFirstError
|
|
)
|
|
{
|
|
//
|
|
// the reason to add this call here is that if installation ends successfully, the directory
|
|
// would be
|
|
// C:\WINDOWS\WINSXS\INSTALLTEMP\15349016
|
|
// +---Manifests
|
|
//
|
|
// and they are "empty" directories (no files). Manifests is a SH dir so set it to be
|
|
// FILE_ATTRIBUTE_NORMAL be more efficient.
|
|
//
|
|
//
|
|
|
|
SetFileAttributesW(dir, FILE_ATTRIBUTE_NORMAL);
|
|
if (RemoveDirectoryW(dir)) // empty dir
|
|
return;
|
|
|
|
//
|
|
// this is the *only* "valid" reason for DeleteDirectory fail
|
|
// but I am not sure about "only"
|
|
//
|
|
DWORD dwLastError = ::GetLastError();
|
|
if ( dwLastError != ERROR_DIR_NOT_EMPTY)
|
|
{
|
|
if (dwFirstError == 0)
|
|
dwFirstError = dwLastError;
|
|
return;
|
|
}
|
|
|
|
const static WCHAR SlashStar[] = L"\\*";
|
|
SIZE_T length = dir.Cch();
|
|
CFindFile findFile;
|
|
|
|
if (!dir.Win32Append(SlashStar, NUMBER_OF(SlashStar) - 1))
|
|
{
|
|
if (dwFirstError == NO_ERROR)
|
|
dwFirstError = ::GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
if (!findFile.Win32FindFirstFile(dir, &wfd))
|
|
{
|
|
if (dwFirstError == NO_ERROR)
|
|
dwFirstError = ::GetLastError();
|
|
goto Exit;
|
|
}
|
|
|
|
do
|
|
{
|
|
if (FusionpIsDotOrDotDot(wfd.cFileName))
|
|
continue;
|
|
|
|
DWORD dwFileAttributes = wfd.dwFileAttributes;
|
|
|
|
// Trim back to the slash...
|
|
dir.Left(length + 1);
|
|
|
|
if (dir.Win32Append(wfd.cFileName, ::wcslen(wfd.cFileName)))
|
|
{
|
|
if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
// recurse
|
|
SxspDeleteDirectoryHelper(dir, wfd, dwFirstError);
|
|
}
|
|
else
|
|
{
|
|
if (!DeleteFileW(dir))
|
|
{
|
|
SetFileAttributesW(dir, FILE_ATTRIBUTE_NORMAL);
|
|
if (!DeleteFileW(dir))
|
|
{
|
|
if (dwFirstError == NO_ERROR)
|
|
{
|
|
//
|
|
// continue even in delete file ( delete files as much as possible)
|
|
// and record the errorCode for first failure
|
|
//
|
|
dwFirstError = ::GetLastError();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (::FindNextFileW(findFile, &wfd));
|
|
if (::GetLastError() != ERROR_NO_MORE_FILES)
|
|
{
|
|
if (dwFirstError == NO_ERROR)
|
|
dwFirstError = ::GetLastError();
|
|
}
|
|
Exit:
|
|
if (!findFile.Win32Close()) // otherwise RemoveDirectory fails
|
|
if (dwFirstError == NO_ERROR)
|
|
dwFirstError = ::GetLastError();
|
|
|
|
dir.Left(length);
|
|
|
|
if (!RemoveDirectoryW(dir)) // the dir must be empty and NORMAL_ATTRIBUTE : ready to delete
|
|
{
|
|
if (dwFirstError == NO_ERROR)
|
|
dwFirstError = ::GetLastError();
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
delete a directory recursively, continues upon errors, but returns
|
|
FALSE if there were any.
|
|
-----------------------------------------------------------------------------*/
|
|
HRESULT
|
|
ca_SxspDeleteDirectory(
|
|
const CStringBuffer &dir
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CStringBuffer mutableDir;
|
|
|
|
WIN32_FIND_DATAW wfd = {0};
|
|
DWORD dwFirstError = ERROR_SUCCESS;
|
|
|
|
IFFALSE_EXIT(mutableDir.Win32Assign(dir));
|
|
|
|
IFFALSE_EXIT(mutableDir.Win32RemoveTrailingPathSeparators());
|
|
|
|
::SxspDeleteDirectoryHelper(
|
|
mutableDir,
|
|
wfd,
|
|
dwFirstError);
|
|
|
|
//
|
|
// Set wFirstError to Teb->LastWin32Error
|
|
//
|
|
if (dwFirstError != ERROR_SUCCESS)
|
|
goto Exit;
|
|
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// function about assembly Identity
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
ca_SxspFormatULONG(
|
|
ULONG ul,
|
|
SIZE_T CchBuffer,
|
|
WCHAR Buffer[],
|
|
SIZE_T *CchWrittenOrRequired
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int cch;
|
|
|
|
if (CchWrittenOrRequired != NULL)
|
|
*CchWrittenOrRequired = 0;
|
|
|
|
PARAMETER_CHECK_NTC(Buffer != NULL);
|
|
|
|
if (CchBuffer < (ULONG_STRING_LENGTH + 1))
|
|
{
|
|
if (CchWrittenOrRequired != NULL)
|
|
*CchWrittenOrRequired = ULONG_STRING_LENGTH + 1;
|
|
|
|
SET_HRERR_AND_EXIT(ERROR_INSUFFICIENT_BUFFER);
|
|
}
|
|
|
|
cch = _snwprintf(Buffer, CchBuffer, ULONG_STRING_FORMAT, ul);
|
|
INTERNAL_ERROR_CHECK_NTC(cch > 0);
|
|
|
|
if (CchWrittenOrRequired != NULL)
|
|
*CchWrittenOrRequired = cch;
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// function about assembly Identity
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#define ASSEMBLY_NAME_VALID_SPECIAL_CHARACTERS L".-"
|
|
#define ASSEMBLY_NAME_PRIM_MAX_LENGTH 64
|
|
#define ASSEMBLY_NAME_VALID_SEPARATORS L"."
|
|
#define ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH 2
|
|
#define ASSEMBLY_NAME_TRIM_INDICATOR L".."
|
|
#define SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE L"no-public-key"
|
|
|
|
BOOL
|
|
IsValidAssemblyNameCharacter(WCHAR ch)
|
|
{
|
|
if (((ch >= L'A') && (ch <= L'Z')) ||
|
|
((ch >= L'a') && (ch <= L'z')) ||
|
|
((ch >= L'0') && (ch <= L'9')) ||
|
|
(wcschr(ASSEMBLY_NAME_VALID_SPECIAL_CHARACTERS, ch)!= NULL))
|
|
{
|
|
return TRUE;
|
|
} else
|
|
return FALSE;
|
|
/*
|
|
if (wcschr(ASSEMBLY_NAME_VALID_SPECIAL_CHARACTERS, ch))
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
*/
|
|
}
|
|
|
|
HRESULT ca_SxspGenerateAssemblyNamePrimeFromName(
|
|
PCWSTR pszAssemblyName,
|
|
SIZE_T CchAssemblyName,
|
|
CBaseStringBuffer *Buffer
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
PWSTR pStart = NULL, pEnd = NULL;
|
|
PWSTR qEnd = NULL, pszBuffer = NULL;
|
|
ULONG i, j, len, ulSpaceLeft;
|
|
ULONG cch;
|
|
PWSTR pLeftEnd = NULL, pRightStart = NULL, PureNameEnd = NULL, PureNameStart = NULL;
|
|
CStringBuffer buffTemp;
|
|
CStringBufferAccessor accessor;
|
|
|
|
PARAMETER_CHECK_NTC(pszAssemblyName != NULL);
|
|
PARAMETER_CHECK_NTC(Buffer != NULL);
|
|
|
|
// See how many characters we need max in the temporary buffer.
|
|
cch = 0;
|
|
|
|
for (i=0; i<CchAssemblyName; i++)
|
|
{
|
|
if (::IsValidAssemblyNameCharacter(pszAssemblyName[i]))
|
|
cch++;
|
|
}
|
|
|
|
IFFALSE_EXIT(buffTemp.Win32ResizeBuffer(cch + 1, eDoNotPreserveBufferContents));
|
|
|
|
accessor.Attach(&buffTemp);
|
|
|
|
pszBuffer = accessor.GetBufferPtr();
|
|
|
|
j = 0;
|
|
for (i=0; i<CchAssemblyName; i++)
|
|
{
|
|
if (::IsValidAssemblyNameCharacter(pszAssemblyName[i]))
|
|
{
|
|
pszBuffer[j] = pszAssemblyName[i];
|
|
j++;
|
|
}
|
|
}
|
|
|
|
ASSERT_NTC(j == cch);
|
|
|
|
pszBuffer[j] = L'\0';
|
|
|
|
// if the name is not too long, just return ;
|
|
if (j < ASSEMBLY_NAME_PRIM_MAX_LENGTH)
|
|
{ // less or equal 64
|
|
IFFALSE_EXIT(Buffer->Win32Assign(pszBuffer, cch));
|
|
}
|
|
else
|
|
{
|
|
// name is too long, have to trim a little bit
|
|
ulSpaceLeft = ASSEMBLY_NAME_PRIM_MAX_LENGTH;
|
|
|
|
PureNameStart = pszBuffer;
|
|
PureNameEnd = pszBuffer + j;
|
|
pLeftEnd = PureNameStart;
|
|
pRightStart = PureNameEnd;
|
|
|
|
while (PureNameStart < PureNameEnd)
|
|
{
|
|
// left end
|
|
pStart = PureNameStart;
|
|
i = 0;
|
|
while ((wcschr(ASSEMBLY_NAME_VALID_SEPARATORS, pStart[i]) == 0) && (pStart+i != pRightStart)) // not a separator character
|
|
i++;
|
|
|
|
pEnd = pStart + i ;
|
|
len = i; // it should be length of WCHAR! not BYTE!!!
|
|
|
|
if (len >= ulSpaceLeft - ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH) {// because we use ".." if trim happen
|
|
pLeftEnd += (ulSpaceLeft - ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH);
|
|
break;
|
|
}
|
|
ulSpaceLeft -= len;
|
|
pLeftEnd = pEnd; // "abc.xxxxxxx" pointing to "c"
|
|
|
|
// right end
|
|
qEnd = PureNameEnd;
|
|
i = 0 ;
|
|
while ((qEnd+i != pLeftEnd) && (wcschr(ASSEMBLY_NAME_VALID_SEPARATORS, qEnd[i]) == 0))
|
|
i--;
|
|
|
|
len = 0 - i;
|
|
if (len >= ulSpaceLeft - ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH) {// because we use ".." if trim happen
|
|
pRightStart -= ulSpaceLeft - ASSEMBLY_NAME_TRIM_INDICATOR_LENGTH;
|
|
break;
|
|
}
|
|
ulSpaceLeft -= len;
|
|
PureNameStart = pLeftEnd + 1;
|
|
PureNameEnd = pRightStart - 1;
|
|
} // end of while
|
|
|
|
IFFALSE_EXIT(Buffer->Win32Assign(pszBuffer, pLeftEnd-pszBuffer));
|
|
IFFALSE_EXIT(Buffer->Win32Append(ASSEMBLY_NAME_TRIM_INDICATOR, NUMBER_OF(ASSEMBLY_NAME_TRIM_INDICATOR) - 1));
|
|
IFFALSE_EXIT(Buffer->Win32Append(pRightStart, ::wcslen(pRightStart))); // till end of the buffer
|
|
}
|
|
|
|
Exit:
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
ca_SxspGenerateSxsPath(
|
|
IN DWORD Flags,
|
|
IN ULONG PathType,
|
|
IN const WCHAR *AssemblyRootDirectory OPTIONAL,
|
|
IN SIZE_T AssemblyRootDirectoryCch,
|
|
IN PCASSEMBLY_IDENTITY pAssemblyIdentity,
|
|
IN OUT CBaseStringBuffer &PathBuffer
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
SIZE_T cch = 0;
|
|
PCWSTR pszAssemblyName=NULL, pszVersion=NULL, pszProcessorArchitecture=NULL, pszLanguage=NULL, pszPolicyFileNameWithoutExt = NULL;
|
|
PCWSTR pszAssemblyStrongName=NULL;
|
|
SIZE_T AssemblyNameCch = 0, AssemblyStrongNameCch=0, VersionCch=0, ProcessorArchitectureCch=0, LanguageCch=0;
|
|
SIZE_T PolicyFileNameWithoutExtCch=0;
|
|
BOOL fNeedSlashAfterRoot = FALSE;
|
|
ULONG IdentityHash;
|
|
BOOL fOmitRoot = ((Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT) != 0);
|
|
BOOL fPartialPath = ((Flags & SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH) != 0);
|
|
|
|
WCHAR HashBuffer[ULONG_STRING_LENGTH + 1];
|
|
SIZE_T HashBufferCch;
|
|
|
|
CSmallStringBuffer NamePrimeBuffer;
|
|
|
|
#if DBG_SXS
|
|
::FusionpDbgPrintEx(
|
|
FUSION_DBG_LEVEL_INFO,
|
|
"SXS.DLL: Entered %s()\n"
|
|
" Flags = 0x%08lx\n"
|
|
" AssemblyRootDirectory = %p\n"
|
|
" AssemblyRootDirectoryCch = %lu\n"
|
|
" PathBuffer = %p\n",
|
|
__FUNCTION__,
|
|
Flags,
|
|
AssemblyRootDirectory,
|
|
AssemblyRootDirectoryCch,
|
|
&PathBuffer);
|
|
#endif // DBG_SXS
|
|
|
|
PARAMETER_CHECK_NTC(
|
|
(PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY) ||
|
|
(PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) ||
|
|
(PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY));
|
|
PARAMETER_CHECK_NTC(pAssemblyIdentity != NULL);
|
|
PARAMETER_CHECK_NTC((Flags & ~(SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION | SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT | SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH)) == 0);
|
|
// Not supplying the assembly root is only legal if you're asking for it to be left out...
|
|
PARAMETER_CHECK_NTC((AssemblyRootDirectoryCch != 0) || (Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_ROOT));
|
|
|
|
// You can't combine SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH with anything else...
|
|
PARAMETER_CHECK_NTC(
|
|
((Flags & SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH) == 0) ||
|
|
((Flags & ~(SXSP_GENERATE_SXS_PATH_FLAG_PARTIAL_PATH)) == 0));
|
|
|
|
// get AssemblyName
|
|
IFFALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(0, pAssemblyIdentity, &s_IdentityAttribute_name, &pszAssemblyName, &AssemblyNameCch));
|
|
INTERNAL_ERROR_CHECK_NTC((pszAssemblyName != NULL) && (AssemblyNameCch != 0));
|
|
|
|
// get AssemblyName' based on AssemblyName
|
|
IFFAILED_EXIT(ca_SxspGenerateAssemblyNamePrimeFromName(pszAssemblyName, AssemblyNameCch, &NamePrimeBuffer));
|
|
|
|
// get Assembly Version
|
|
IFFALSE_EXIT(::SxspGetAssemblyIdentityAttributeValue(
|
|
SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL, // for policy_lookup, no version is used
|
|
pAssemblyIdentity,
|
|
&s_IdentityAttribute_version,
|
|
&pszVersion,
|
|
&VersionCch));
|
|
if ((Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION) || (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY))
|
|
{
|
|
// for policy file, version of the policy file is used as policy filename
|
|
pszPolicyFileNameWithoutExt = pszVersion;
|
|
PolicyFileNameWithoutExtCch = VersionCch;
|
|
pszVersion = NULL;
|
|
VersionCch = 0;
|
|
}
|
|
else
|
|
{
|
|
PARAMETER_CHECK_NTC((pszVersion != NULL) && (VersionCch != 0));
|
|
}
|
|
|
|
// get Assembly Langage
|
|
IFFALSE_EXIT(
|
|
::SxspGetAssemblyIdentityAttributeValue(
|
|
SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
|
|
pAssemblyIdentity,
|
|
&s_IdentityAttribute_language,
|
|
&pszLanguage,
|
|
&LanguageCch));
|
|
if (pszLanguage == NULL)
|
|
{
|
|
pszLanguage = SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_LANGUAGE_MISSING_VALUE;
|
|
LanguageCch = NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_LANGUAGE_MISSING_VALUE) - 1;
|
|
}
|
|
|
|
// get Assembly ProcessorArchitecture
|
|
IFFALSE_EXIT(
|
|
::SxspGetAssemblyIdentityAttributeValue(
|
|
SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
|
|
pAssemblyIdentity,
|
|
&s_IdentityAttribute_processorArchitecture,
|
|
&pszProcessorArchitecture,
|
|
&ProcessorArchitectureCch));
|
|
if (pszProcessorArchitecture == NULL)
|
|
{
|
|
pszProcessorArchitecture = L"data";
|
|
ProcessorArchitectureCch = 4;
|
|
}
|
|
|
|
// get Assembly StrongName
|
|
IFFALSE_EXIT(
|
|
::SxspGetAssemblyIdentityAttributeValue(
|
|
SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
|
|
pAssemblyIdentity,
|
|
&s_IdentityAttribute_publicKeyToken,
|
|
&pszAssemblyStrongName,
|
|
&AssemblyStrongNameCch));
|
|
if (pszAssemblyStrongName == NULL)
|
|
{
|
|
pszAssemblyStrongName = SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE;
|
|
AssemblyStrongNameCch = NUMBER_OF(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_PUBLICKEY_MISSING_VALUE) - 1;
|
|
}
|
|
|
|
//get Assembly Hash String
|
|
if ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY) || (Flags & SXSP_GENERATE_SXS_PATH_FLAG_OMIT_VERSION))
|
|
{
|
|
IFFALSE_EXIT(::SxspHashAssemblyIdentityForPolicy(0, pAssemblyIdentity, IdentityHash));
|
|
}
|
|
else
|
|
{
|
|
IFFALSE_EXIT(::SxsHashAssemblyIdentity(0, pAssemblyIdentity, &IdentityHash));
|
|
}
|
|
|
|
IFFAILED_EXIT(ca_SxspFormatULONG(IdentityHash, NUMBER_OF(HashBuffer), HashBuffer, &HashBufferCch));
|
|
INTERNAL_ERROR_CHECK_NTC(HashBufferCch == ULONG_STRING_LENGTH);
|
|
|
|
if (!fOmitRoot)
|
|
{
|
|
// If the assembly root was not passed in, get it.
|
|
fNeedSlashAfterRoot = (! ::FusionpIsPathSeparator(AssemblyRootDirectory[AssemblyRootDirectoryCch-1]));
|
|
}
|
|
else
|
|
{
|
|
// If we don't want to include the root, then don't account for it below...
|
|
AssemblyRootDirectoryCch = 0;
|
|
fNeedSlashAfterRoot = FALSE;
|
|
}
|
|
|
|
// this computation can be off by one or a few, it's an optimization
|
|
// to pregrow a string buffer
|
|
cch =
|
|
AssemblyRootDirectoryCch + // "C:\WINNT\WinSxS\"
|
|
(fNeedSlashAfterRoot ? 1 : 0);
|
|
|
|
switch (PathType)
|
|
{
|
|
case SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST:
|
|
// Wacky parens and ... - 1) + 1) to reinforce that it's the number of
|
|
// characters in the string not including the null and then an extra separator.
|
|
cch += (NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1) + 1;
|
|
break;
|
|
|
|
case SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY:
|
|
// Wacky parens and ... - 1) + 1) to reinforce that it's the number of
|
|
// characters in the string not including the null and then an extra separator.
|
|
cch += (NUMBER_OF(POLICY_ROOT_DIRECTORY_NAME) - 1) + 1;
|
|
break;
|
|
}
|
|
|
|
cch++;
|
|
|
|
// fPartialPath means that we don't actually want to take the assembly's identity into
|
|
// account; the caller just wants the path to the manifests or policies directories.
|
|
if (!fPartialPath)
|
|
{
|
|
cch +=
|
|
ProcessorArchitectureCch + // "x86"
|
|
1 + // "_"
|
|
NamePrimeBuffer.Cch() + // "FooBar"
|
|
1 + // "_"
|
|
AssemblyStrongNameCch + // StrongName
|
|
1 + // "_"
|
|
VersionCch + // "5.6.2900.42"
|
|
1 + // "_"
|
|
LanguageCch + // "0409"
|
|
1 + // "_"
|
|
HashBufferCch;
|
|
|
|
if (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST)
|
|
{
|
|
cch += NUMBER_OF(ASSEMBLY_LONGEST_MANIFEST_FILE_NAME_SUFFIX); // ".manifest\0"
|
|
}
|
|
else if (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY)
|
|
{
|
|
// "_" has already reserve space for "\"
|
|
cch += PolicyFileNameWithoutExtCch;
|
|
cch += NUMBER_OF(ASSEMBLY_POLICY_FILE_NAME_SUFFIX); // ".policy\0"
|
|
}
|
|
else { // pathType must be SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY
|
|
|
|
// if (!fOmitRoot)
|
|
// cch++;
|
|
cch++; // trailing null character
|
|
}
|
|
}
|
|
|
|
// We try to ensure that the buffer is big enough up front so that we don't have to do any
|
|
// dynamic reallocation during the actual process.
|
|
IFFALSE_EXIT(PathBuffer.Win32ResizeBuffer(cch, eDoNotPreserveBufferContents));
|
|
|
|
// Note that since when GENERATE_ASSEMBLY_PATH_OMIT_ROOT is set, we force AssemblyRootDirectoryCch to zero
|
|
// and fNeedSlashAfterRoot to FALSE, so the first two entries in this concatenation actually don't
|
|
// contribute anything to the string constructed.
|
|
if (fPartialPath)
|
|
{
|
|
IFFALSE_EXIT(PathBuffer.Win32AssignW(5,
|
|
AssemblyRootDirectory, static_cast<INT>(AssemblyRootDirectoryCch), // "C:\WINNT\WINSXS"
|
|
L"\\", (fNeedSlashAfterRoot ? 1 : 0), // optional '\'
|
|
// manifests subdir
|
|
MANIFEST_ROOT_DIRECTORY_NAME, ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) ? NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) -1 : 0), // "manifests"
|
|
// policies subdir
|
|
POLICY_ROOT_DIRECTORY_NAME, ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY)? NUMBER_OF(POLICY_ROOT_DIRECTORY_NAME) - 1 : 0), // "policies"
|
|
L"\\", (((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) || (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY)) ? 1 : 0)
|
|
)); // optional '\'
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// create one of below
|
|
// (1) fully-qualified manifest filename,
|
|
// eg, [C:\WINNT\WinSxS\]Manifests\X86_DynamicDll_6595b64144ccf1df_2.0.0.0_en-us_2f433926.Manifest
|
|
// (2) fully-qualified policy filename,
|
|
// eg, [C:\WINNT\WinSxS\]Policies\x86_policy.1.0.DynamicDll_b54bc117ce08a1e8_en-us_d51541cb\1.1.0.0.cat
|
|
// (3) fully-qulified assembly name (w. or w/o a version)
|
|
// eg, [C:\WINNT\WinSxS\]x86_DynamicDll_6595b64144ccf1df_6.0.0.0_x-ww_ff9986d7
|
|
//
|
|
IFFALSE_EXIT(
|
|
PathBuffer.Win32AssignW(17,
|
|
AssemblyRootDirectory, static_cast<INT>(AssemblyRootDirectoryCch), // "C:\WINNT\WINSXS"
|
|
L"\\", (fNeedSlashAfterRoot ? 1 : 0), // optional '\'
|
|
MANIFEST_ROOT_DIRECTORY_NAME, ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) ? NUMBER_OF(MANIFEST_ROOT_DIRECTORY_NAME) - 1 : 0),
|
|
POLICY_ROOT_DIRECTORY_NAME, ((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY) ? NUMBER_OF(POLICY_ROOT_DIRECTORY_NAME) - 1 : 0),
|
|
L"\\", (((PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST) || (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY)) ? 1 : 0), // optional '\'
|
|
pszProcessorArchitecture, static_cast<INT>(ProcessorArchitectureCch),
|
|
L"_", 1,
|
|
static_cast<PCWSTR>(NamePrimeBuffer), static_cast<INT>(NamePrimeBuffer.Cch()),
|
|
L"_", 1,
|
|
pszAssemblyStrongName, static_cast<INT>(AssemblyStrongNameCch),
|
|
L"_", (VersionCch != 0) ? 1 : 0,
|
|
pszVersion, static_cast<INT>(VersionCch),
|
|
L"_", 1,
|
|
pszLanguage, static_cast<INT>(LanguageCch),
|
|
L"_", 1,
|
|
static_cast<PCWSTR>(HashBuffer), static_cast<INT>(HashBufferCch),
|
|
L"\\", ((fOmitRoot ||(PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST)) ? 0 : 1)));
|
|
|
|
if (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST)
|
|
IFFALSE_EXIT(PathBuffer.Win32Append(ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX, NUMBER_OF(ASSEMBLY_MANIFEST_FILE_NAME_SUFFIX) - 1));
|
|
else if (PathType == SXSP_GENERATE_SXS_PATH_PATHTYPE_POLICY)
|
|
{
|
|
if ((pszPolicyFileNameWithoutExt != NULL) && (PolicyFileNameWithoutExtCch >0))
|
|
{
|
|
IFFALSE_EXIT(PathBuffer.Win32Append(pszPolicyFileNameWithoutExt, PolicyFileNameWithoutExtCch));
|
|
IFFALSE_EXIT(PathBuffer.Win32Append(ASSEMBLY_POLICY_FILE_NAME_SUFFIX, NUMBER_OF(ASSEMBLY_POLICY_FILE_NAME_SUFFIX) - 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ca_SxspDetermineAssemblyType(
|
|
PCASSEMBLY_IDENTITY pAssemblyIdentity,
|
|
BOOL &fIsWin32,
|
|
BOOL &fIsWin32Policy
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
PCWSTR pcwszType = NULL;
|
|
SIZE_T cchType = 0;
|
|
|
|
fIsWin32 = FALSE;
|
|
fIsWin32Policy = FALSE;
|
|
|
|
PARAMETER_CHECK_NTC(pAssemblyIdentity != NULL);
|
|
|
|
IFFALSE_EXIT(
|
|
::SxspGetAssemblyIdentityAttributeValue(
|
|
SXSP_GET_ASSEMBLY_IDENTITY_ATTRIBUTE_VALUE_FLAG_NOT_FOUND_RETURNS_NULL,
|
|
pAssemblyIdentity,
|
|
&s_IdentityAttribute_type,
|
|
&pcwszType,
|
|
&cchType));
|
|
|
|
fIsWin32 = (::FusionpCompareStrings(pcwszType, cchType, ASSEMBLY_TYPE_WIN32, ASSEMBLY_TYPE_WIN32_CCH, false) == 0);
|
|
if (!fIsWin32)
|
|
fIsWin32Policy = (::FusionpCompareStrings(pcwszType, cchType, ASSEMBLY_TYPE_WIN32_POLICY, ASSEMBLY_TYPE_WIN32_POLICY_CCH, false) == 0);
|
|
|
|
Exit:
|
|
return hr;
|
|
}
|