859 lines
25 KiB
C
859 lines
25 KiB
C
/*
|
|
* IAssemblyCache implementation
|
|
*
|
|
* Copyright 2010 Hans Leidekker for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
|
|
#define COBJMACROS
|
|
#define INITGUID
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "ole2.h"
|
|
#include "winsxs.h"
|
|
#include "msxml2.h"
|
|
|
|
#include "wine/debug.h"
|
|
#include "wine/list.h"
|
|
#include "wine/unicode.h"
|
|
#include "sxs_private.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(sxs);
|
|
|
|
static const WCHAR cache_mutex_nameW[] =
|
|
{'_','_','W','I','N','E','_','S','X','S','_','C','A','C','H','E','_','M','U','T','E','X','_','_',0};
|
|
|
|
static const WCHAR win32W[] = {'w','i','n','3','2',0};
|
|
static const WCHAR win32_policyW[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
|
|
static const WCHAR backslashW[] = {'\\',0};
|
|
|
|
struct cache
|
|
{
|
|
IAssemblyCache IAssemblyCache_iface;
|
|
LONG refs;
|
|
HANDLE lock;
|
|
};
|
|
|
|
static inline struct cache *impl_from_IAssemblyCache(IAssemblyCache *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct cache, IAssemblyCache_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI cache_QueryInterface(
|
|
IAssemblyCache *iface,
|
|
REFIID riid,
|
|
void **obj )
|
|
{
|
|
struct cache *cache = impl_from_IAssemblyCache(iface);
|
|
|
|
TRACE("%p, %s, %p\n", cache, debugstr_guid(riid), obj);
|
|
|
|
*obj = NULL;
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IAssemblyCache))
|
|
{
|
|
IUnknown_AddRef( iface );
|
|
*obj = cache;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI cache_AddRef( IAssemblyCache *iface )
|
|
{
|
|
struct cache *cache = impl_from_IAssemblyCache(iface);
|
|
return InterlockedIncrement( &cache->refs );
|
|
}
|
|
|
|
static ULONG WINAPI cache_Release( IAssemblyCache *iface )
|
|
{
|
|
struct cache *cache = impl_from_IAssemblyCache(iface);
|
|
ULONG refs = InterlockedDecrement( &cache->refs );
|
|
|
|
if (!refs)
|
|
{
|
|
TRACE("destroying %p\n", cache);
|
|
CloseHandle( cache->lock );
|
|
HeapFree( GetProcessHeap(), 0, cache );
|
|
}
|
|
return refs;
|
|
}
|
|
|
|
static unsigned int build_sxs_path( WCHAR *path )
|
|
{
|
|
static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\',0};
|
|
unsigned int len = GetWindowsDirectoryW( path, MAX_PATH );
|
|
|
|
memcpy( path + len, winsxsW, sizeof(winsxsW) );
|
|
return len + sizeof(winsxsW) / sizeof(winsxsW[0]) - 1;
|
|
}
|
|
|
|
static WCHAR *build_assembly_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
|
|
const WCHAR *version, unsigned int *len )
|
|
{
|
|
static const WCHAR fmtW[] =
|
|
{'%','s','_','%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
|
|
unsigned int buflen = sizeof(fmtW) / sizeof(fmtW[0]);
|
|
WCHAR *ret, *p;
|
|
|
|
buflen += strlenW( arch );
|
|
buflen += strlenW( name );
|
|
buflen += strlenW( token );
|
|
buflen += strlenW( version );
|
|
if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL;
|
|
*len = sprintfW( ret, fmtW, arch, name, token, version );
|
|
for (p = ret; *p; p++) *p = tolowerW( *p );
|
|
return ret;
|
|
}
|
|
|
|
static WCHAR *build_manifest_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
|
|
const WCHAR *version )
|
|
{
|
|
static const WCHAR fmtW[] =
|
|
{'%','s','m','a','n','i','f','e','s','t','s','\\','%','s','.','m','a','n','i','f','e','s','t',0};
|
|
WCHAR *path = NULL, *ret, sxsdir[MAX_PATH];
|
|
unsigned int len;
|
|
|
|
if (!(path = build_assembly_name( arch, name, token, version, &len ))) return NULL;
|
|
len += sizeof(fmtW) / sizeof(fmtW[0]);
|
|
len += build_sxs_path( sxsdir );
|
|
if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, path );
|
|
return NULL;
|
|
}
|
|
sprintfW( ret, fmtW, sxsdir, path );
|
|
HeapFree( GetProcessHeap(), 0, path );
|
|
return ret;
|
|
}
|
|
|
|
static WCHAR *build_policy_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
|
|
unsigned int *len )
|
|
{
|
|
static const WCHAR fmtW[] =
|
|
{'%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
|
|
unsigned int buflen = sizeof(fmtW) / sizeof(fmtW[0]);
|
|
WCHAR *ret, *p;
|
|
|
|
buflen += strlenW( arch );
|
|
buflen += strlenW( name );
|
|
buflen += strlenW( token );
|
|
if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL;
|
|
*len = sprintfW( ret, fmtW, arch, name, token );
|
|
for (p = ret; *p; p++) *p = tolowerW( *p );
|
|
return ret;
|
|
}
|
|
|
|
static WCHAR *build_policy_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
|
|
const WCHAR *version )
|
|
{
|
|
static const WCHAR fmtW[] =
|
|
{'%','s','p','o','l','i','c','i','e','s','\\','%','s','\\','%','s','.','p','o','l','i','c','y',0};
|
|
WCHAR *path = NULL, *ret, sxsdir[MAX_PATH];
|
|
unsigned int len;
|
|
|
|
if (!(path = build_policy_name( arch, name, token, &len ))) return NULL;
|
|
len += sizeof(fmtW) / sizeof(fmtW[0]);
|
|
len += build_sxs_path( sxsdir );
|
|
len += strlenW( version );
|
|
if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, path );
|
|
return NULL;
|
|
}
|
|
sprintfW( ret, fmtW, sxsdir, path, version );
|
|
HeapFree( GetProcessHeap(), 0, path );
|
|
return ret;
|
|
}
|
|
|
|
static void cache_lock( struct cache *cache )
|
|
{
|
|
WaitForSingleObject( cache->lock, INFINITE );
|
|
}
|
|
|
|
static void cache_unlock( struct cache *cache )
|
|
{
|
|
ReleaseMutex( cache->lock );
|
|
}
|
|
|
|
#define ASSEMBLYINFO_FLAG_INSTALLED 1
|
|
|
|
static HRESULT WINAPI cache_QueryAssemblyInfo(
|
|
IAssemblyCache *iface,
|
|
DWORD flags,
|
|
LPCWSTR assembly_name,
|
|
ASSEMBLY_INFO *info )
|
|
{
|
|
struct cache *cache = impl_from_IAssemblyCache( iface );
|
|
IAssemblyName *name_obj;
|
|
const WCHAR *arch, *name, *token, *type, *version;
|
|
WCHAR *p, *path = NULL;
|
|
unsigned int len;
|
|
HRESULT hr;
|
|
|
|
TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(assembly_name), info);
|
|
|
|
if (flags || (info && info->cbAssemblyInfo != sizeof(*info)))
|
|
return E_INVALIDARG;
|
|
|
|
hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, 0 );
|
|
if (FAILED( hr ))
|
|
return hr;
|
|
|
|
arch = get_name_attribute( name_obj, NAME_ATTR_ID_ARCH );
|
|
name = get_name_attribute( name_obj, NAME_ATTR_ID_NAME );
|
|
token = get_name_attribute( name_obj, NAME_ATTR_ID_TOKEN );
|
|
type = get_name_attribute( name_obj, NAME_ATTR_ID_TYPE );
|
|
version = get_name_attribute( name_obj, NAME_ATTR_ID_VERSION );
|
|
if (!arch || !name || !token || !type || !version)
|
|
{
|
|
IAssemblyName_Release( name_obj );
|
|
return HRESULT_FROM_WIN32( ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE );
|
|
}
|
|
if (!info)
|
|
{
|
|
IAssemblyName_Release( name_obj );
|
|
return S_OK;
|
|
}
|
|
cache_lock( cache );
|
|
|
|
if (!strcmpW( type, win32W )) path = build_manifest_path( arch, name, token, version );
|
|
else if (!strcmpW( type, win32_policyW )) path = build_policy_path( arch, name, token, version );
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32( ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE );
|
|
goto done;
|
|
}
|
|
if (!path)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
hr = S_OK;
|
|
if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES) /* FIXME: better check */
|
|
{
|
|
info->dwAssemblyFlags = ASSEMBLYINFO_FLAG_INSTALLED;
|
|
TRACE("assembly is installed\n");
|
|
}
|
|
if ((p = strrchrW( path, '\\' ))) *p = 0;
|
|
len = strlenW( path ) + 1;
|
|
if (info->pszCurrentAssemblyPathBuf)
|
|
{
|
|
if (info->cchBuf < len)
|
|
{
|
|
info->cchBuf = len;
|
|
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
|
|
}
|
|
else strcpyW( info->pszCurrentAssemblyPathBuf, path );
|
|
}
|
|
|
|
done:
|
|
HeapFree( GetProcessHeap(), 0, path );
|
|
IAssemblyName_Release( name_obj );
|
|
cache_unlock( cache );
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI cache_CreateAssemblyCacheItem(
|
|
IAssemblyCache *iface,
|
|
DWORD flags,
|
|
PVOID reserved,
|
|
IAssemblyCacheItem **item,
|
|
LPCWSTR name )
|
|
{
|
|
FIXME("%p, 0x%08x, %p, %p, %s\n", iface, flags, reserved, item, debugstr_w(name));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI cache_Reserved(
|
|
IAssemblyCache *iface,
|
|
IUnknown **reserved)
|
|
{
|
|
FIXME("%p\n", reserved);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static BSTR get_attribute_value( IXMLDOMNamedNodeMap *map, const WCHAR *value_name )
|
|
{
|
|
HRESULT hr;
|
|
IXMLDOMNode *attr;
|
|
VARIANT var;
|
|
BSTR str;
|
|
|
|
str = SysAllocString( value_name );
|
|
hr = IXMLDOMNamedNodeMap_getNamedItem( map, str, &attr );
|
|
SysFreeString( str );
|
|
if (hr != S_OK) return NULL;
|
|
|
|
hr = IXMLDOMNode_get_nodeValue( attr, &var );
|
|
IXMLDOMNode_Release( attr );
|
|
if (hr != S_OK) return NULL;
|
|
if (V_VT(&var) != VT_BSTR)
|
|
{
|
|
VariantClear( &var );
|
|
return NULL;
|
|
}
|
|
TRACE("%s=%s\n", debugstr_w(value_name), debugstr_w(V_BSTR( &var )));
|
|
return V_BSTR( &var );
|
|
}
|
|
|
|
struct file
|
|
{
|
|
struct list entry;
|
|
BSTR name;
|
|
};
|
|
|
|
struct assembly
|
|
{
|
|
BSTR type;
|
|
BSTR name;
|
|
BSTR version;
|
|
BSTR arch;
|
|
BSTR token;
|
|
struct list files;
|
|
};
|
|
|
|
static void free_assembly( struct assembly *assembly )
|
|
{
|
|
struct list *item, *cursor;
|
|
|
|
if (!assembly) return;
|
|
SysFreeString( assembly->type );
|
|
SysFreeString( assembly->name );
|
|
SysFreeString( assembly->version );
|
|
SysFreeString( assembly->arch );
|
|
SysFreeString( assembly->token );
|
|
LIST_FOR_EACH_SAFE( item, cursor, &assembly->files )
|
|
{
|
|
struct file *file = LIST_ENTRY( item, struct file, entry );
|
|
list_remove( &file->entry );
|
|
SysFreeString( file->name );
|
|
HeapFree( GetProcessHeap(), 0, file );
|
|
}
|
|
HeapFree( GetProcessHeap(), 0, assembly );
|
|
}
|
|
|
|
static HRESULT parse_files( IXMLDOMDocument *doc, struct assembly *assembly )
|
|
{
|
|
static const WCHAR fileW[] = {'f','i','l','e',0};
|
|
static const WCHAR nameW[] = {'n','a','m','e',0};
|
|
IXMLDOMNamedNodeMap *attrs;
|
|
IXMLDOMNodeList *list;
|
|
IXMLDOMNode *node;
|
|
struct file *f;
|
|
BSTR str;
|
|
HRESULT hr;
|
|
LONG len;
|
|
|
|
str = SysAllocString( fileW );
|
|
hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
|
|
SysFreeString( str );
|
|
if (hr != S_OK) return hr;
|
|
|
|
hr = IXMLDOMNodeList_get_length( list, &len );
|
|
if (hr != S_OK) goto done;
|
|
TRACE("found %d files\n", len);
|
|
if (!len)
|
|
{
|
|
hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
hr = IXMLDOMNodeList_nextNode( list, &node );
|
|
if (hr != S_OK || !node)
|
|
{
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
/* FIXME: validate node type */
|
|
|
|
hr = IXMLDOMNode_get_attributes( node, &attrs );
|
|
IXMLDOMNode_Release( node );
|
|
if (hr != S_OK)
|
|
goto done;
|
|
|
|
if (!(f = HeapAlloc( GetProcessHeap(), 0, sizeof(struct file) )))
|
|
{
|
|
IXMLDOMNamedNodeMap_Release( attrs );
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
|
|
f->name = get_attribute_value( attrs, nameW );
|
|
IXMLDOMNamedNodeMap_Release( attrs );
|
|
if (!f->name)
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, f );
|
|
hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
|
|
goto done;
|
|
}
|
|
list_add_tail( &assembly->files, &f->entry );
|
|
}
|
|
|
|
if (list_empty( &assembly->files ))
|
|
{
|
|
WARN("no files found\n");
|
|
hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
|
|
}
|
|
|
|
done:
|
|
IXMLDOMNodeList_Release( list );
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT parse_assembly( IXMLDOMDocument *doc, struct assembly **assembly )
|
|
{
|
|
static const WCHAR identityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
|
|
static const WCHAR typeW[] = {'t','y','p','e',0};
|
|
static const WCHAR nameW[] = {'n','a','m','e',0};
|
|
static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
|
|
static const WCHAR architectureW[] = {'p','r','o','c','e','s','s','o','r','A','r','c','h','i','t','e','c','t','u','r','e',0};
|
|
static const WCHAR tokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
|
|
IXMLDOMNodeList *list = NULL;
|
|
IXMLDOMNode *node = NULL;
|
|
IXMLDOMNamedNodeMap *attrs = NULL;
|
|
struct assembly *a = NULL;
|
|
BSTR str;
|
|
HRESULT hr;
|
|
LONG len;
|
|
|
|
str = SysAllocString( identityW );
|
|
hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
|
|
SysFreeString( str );
|
|
if (hr != S_OK) goto done;
|
|
|
|
hr = IXMLDOMNodeList_get_length( list, &len );
|
|
if (hr != S_OK) goto done;
|
|
if (!len)
|
|
{
|
|
hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
|
|
goto done;
|
|
}
|
|
hr = IXMLDOMNodeList_nextNode( list, &node );
|
|
if (hr != S_OK) goto done;
|
|
if (!node)
|
|
{
|
|
hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
|
|
goto done;
|
|
}
|
|
if (!(a = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct assembly) )))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto done;
|
|
}
|
|
list_init( &a->files );
|
|
|
|
hr = IXMLDOMNode_get_attributes( node, &attrs );
|
|
if (hr != S_OK) goto done;
|
|
|
|
a->type = get_attribute_value( attrs, typeW );
|
|
a->name = get_attribute_value( attrs, nameW );
|
|
a->version = get_attribute_value( attrs, versionW );
|
|
a->arch = get_attribute_value( attrs, architectureW );
|
|
a->token = get_attribute_value( attrs, tokenW );
|
|
|
|
if (!a->type || (strcmpW( a->type, win32W ) && strcmpW( a->type, win32_policyW )) ||
|
|
!a->name || !a->version || !a->arch || !a->token)
|
|
{
|
|
WARN("invalid win32 assembly\n");
|
|
hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
|
|
goto done;
|
|
}
|
|
if (!strcmpW( a->type, win32W )) hr = parse_files( doc, a );
|
|
|
|
done:
|
|
if (attrs) IXMLDOMNamedNodeMap_Release( attrs );
|
|
if (node) IXMLDOMNode_Release( node );
|
|
if (list) IXMLDOMNodeList_Release( list );
|
|
if (hr == S_OK) *assembly = a;
|
|
else free_assembly( a );
|
|
return hr;
|
|
}
|
|
|
|
static WCHAR *build_policy_filename( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
|
|
const WCHAR *version )
|
|
{
|
|
static const WCHAR policiesW[] = {'p','o','l','i','c','i','e','s','\\',0};
|
|
static const WCHAR suffixW[] = {'.','p','o','l','i','c','y',0};
|
|
WCHAR sxsdir[MAX_PATH], *ret, *fullname;
|
|
unsigned int len;
|
|
|
|
if (!(fullname = build_policy_name( arch, name, token, &len ))) return NULL;
|
|
len += build_sxs_path( sxsdir );
|
|
len += sizeof(policiesW) / sizeof(policiesW[0]) - 1;
|
|
len += strlenW( version );
|
|
len += sizeof(suffixW) / sizeof(suffixW[0]) - 1;
|
|
if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, fullname );
|
|
return NULL;
|
|
}
|
|
strcpyW( ret, sxsdir );
|
|
strcatW( ret, policiesW );
|
|
CreateDirectoryW( ret, NULL );
|
|
strcatW( ret, name );
|
|
CreateDirectoryW( ret, NULL );
|
|
strcatW( ret, backslashW );
|
|
strcatW( ret, version );
|
|
strcatW( ret, suffixW );
|
|
|
|
HeapFree( GetProcessHeap(), 0, fullname );
|
|
return ret;
|
|
}
|
|
|
|
static HRESULT install_policy( const WCHAR *manifest, struct assembly *assembly )
|
|
{
|
|
WCHAR *dst;
|
|
BOOL ret;
|
|
|
|
/* FIXME: handle catalog file */
|
|
|
|
dst = build_policy_filename( assembly->arch, assembly->name, assembly->token, assembly->version );
|
|
if (!dst) return E_OUTOFMEMORY;
|
|
|
|
ret = CopyFileW( manifest, dst, FALSE );
|
|
HeapFree( GetProcessHeap(), 0, dst );
|
|
if (!ret)
|
|
{
|
|
HRESULT hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
WARN("failed to copy policy manifest file 0x%08x\n", hr);
|
|
return hr;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static WCHAR *build_source_filename( const WCHAR *manifest, struct file *file )
|
|
{
|
|
WCHAR *src;
|
|
const WCHAR *p;
|
|
int len;
|
|
|
|
p = strrchrW( manifest, '\\' );
|
|
if (!p) p = strrchrW( manifest, '/' );
|
|
if (!p) return strdupW( manifest );
|
|
|
|
len = p - manifest + 1;
|
|
if (!(src = HeapAlloc( GetProcessHeap(), 0, (len + strlenW( file->name ) + 1) * sizeof(WCHAR) )))
|
|
return NULL;
|
|
|
|
memcpy( src, manifest, len * sizeof(WCHAR) );
|
|
strcpyW( src + len, file->name );
|
|
return src;
|
|
}
|
|
|
|
static WCHAR *build_manifest_filename( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
|
|
const WCHAR *version )
|
|
{
|
|
static const WCHAR manifestsW[] = {'m','a','n','i','f','e','s','t','s','\\',0};
|
|
static const WCHAR suffixW[] = {'.','m','a','n','i','f','e','s','t',0};
|
|
WCHAR sxsdir[MAX_PATH], *ret, *fullname;
|
|
unsigned int len;
|
|
|
|
if (!(fullname = build_assembly_name( arch, name, token, version, &len ))) return NULL;
|
|
len += build_sxs_path( sxsdir );
|
|
len += sizeof(manifestsW) / sizeof(manifestsW[0]) - 1;
|
|
len += sizeof(suffixW) / sizeof(suffixW[0]) - 1;
|
|
if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, fullname );
|
|
return NULL;
|
|
}
|
|
strcpyW( ret, sxsdir );
|
|
strcatW( ret, manifestsW );
|
|
strcatW( ret, fullname );
|
|
strcatW( ret, suffixW );
|
|
|
|
HeapFree( GetProcessHeap(), 0, fullname );
|
|
return ret;
|
|
}
|
|
|
|
static HRESULT load_manifest( IXMLDOMDocument *doc, const WCHAR *filename )
|
|
{
|
|
HRESULT hr;
|
|
VARIANT var;
|
|
VARIANT_BOOL b;
|
|
BSTR str;
|
|
|
|
str = SysAllocString( filename );
|
|
VariantInit( &var );
|
|
V_VT( &var ) = VT_BSTR;
|
|
V_BSTR( &var ) = str;
|
|
hr = IXMLDOMDocument_load( doc, var, &b );
|
|
SysFreeString( str );
|
|
if (hr != S_OK) return hr;
|
|
if (!b)
|
|
{
|
|
WARN("failed to load manifest\n");
|
|
return S_FALSE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT install_assembly( const WCHAR *manifest, struct assembly *assembly )
|
|
{
|
|
WCHAR sxsdir[MAX_PATH], *p, *name, *dst, *src;
|
|
unsigned int len, len_name, len_sxsdir = build_sxs_path( sxsdir );
|
|
struct file *file;
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
BOOL ret;
|
|
|
|
dst = build_manifest_filename( assembly->arch, assembly->name, assembly->token, assembly->version );
|
|
if (!dst) return E_OUTOFMEMORY;
|
|
|
|
ret = CopyFileW( manifest, dst, FALSE );
|
|
HeapFree( GetProcessHeap(), 0, dst );
|
|
if (!ret)
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
WARN("failed to copy manifest file 0x%08x\n", hr);
|
|
return hr;
|
|
}
|
|
|
|
name = build_assembly_name( assembly->arch, assembly->name, assembly->token, assembly->version,
|
|
&len_name );
|
|
if (!name) return E_OUTOFMEMORY;
|
|
|
|
/* FIXME: this should be a transaction */
|
|
LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
|
|
{
|
|
if (!(src = build_source_filename( manifest, file ))) goto done;
|
|
|
|
len = len_sxsdir + len_name + strlenW( file->name );
|
|
if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) )))
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, src );
|
|
goto done;
|
|
}
|
|
strcpyW( dst, sxsdir );
|
|
strcatW( dst, name );
|
|
CreateDirectoryW( dst, NULL );
|
|
|
|
strcatW( dst, backslashW );
|
|
strcatW( dst, file->name );
|
|
for (p = dst; *p; p++) *p = tolowerW( *p );
|
|
|
|
ret = CopyFileW( src, dst, FALSE );
|
|
HeapFree( GetProcessHeap(), 0, src );
|
|
HeapFree( GetProcessHeap(), 0, dst );
|
|
if (!ret)
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
WARN("failed to copy file 0x%08x\n", hr);
|
|
goto done;
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
done:
|
|
HeapFree( GetProcessHeap(), 0, name );
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI cache_InstallAssembly(
|
|
IAssemblyCache *iface,
|
|
DWORD flags,
|
|
LPCWSTR path,
|
|
LPCFUSION_INSTALL_REFERENCE ref )
|
|
{
|
|
struct cache *cache = impl_from_IAssemblyCache( iface );
|
|
HRESULT hr, init;
|
|
IXMLDOMDocument *doc = NULL;
|
|
struct assembly *assembly = NULL;
|
|
|
|
TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(path), ref);
|
|
|
|
cache_lock( cache );
|
|
init = CoInitialize( NULL );
|
|
|
|
hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
|
|
if (hr != S_OK)
|
|
goto done;
|
|
|
|
if ((hr = load_manifest( doc, path )) != S_OK) goto done;
|
|
if ((hr = parse_assembly( doc, &assembly )) != S_OK) goto done;
|
|
|
|
/* FIXME: verify name attributes */
|
|
|
|
if (!strcmpW( assembly->type, win32_policyW ))
|
|
hr = install_policy( path, assembly );
|
|
else
|
|
hr = install_assembly( path, assembly );
|
|
|
|
done:
|
|
free_assembly( assembly );
|
|
if (doc) IXMLDOMDocument_Release( doc );
|
|
if (SUCCEEDED(init)) CoUninitialize();
|
|
cache_unlock( cache );
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT uninstall_assembly( struct assembly *assembly )
|
|
{
|
|
WCHAR sxsdir[MAX_PATH], *name, *dirname, *filename;
|
|
unsigned int len, len_name, len_sxsdir = build_sxs_path( sxsdir );
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
struct file *file;
|
|
|
|
name = build_assembly_name( assembly->arch, assembly->name, assembly->token, assembly->version,
|
|
&len_name );
|
|
if (!name) return E_OUTOFMEMORY;
|
|
if (!(dirname = HeapAlloc( GetProcessHeap(), 0, (len_sxsdir + len_name + 1) * sizeof(WCHAR) )))
|
|
goto done;
|
|
strcpyW( dirname, sxsdir );
|
|
strcpyW( dirname + len_sxsdir, name );
|
|
|
|
LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
|
|
{
|
|
len = len_sxsdir + len_name + 1 + strlenW( file->name );
|
|
if (!(filename = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) goto done;
|
|
strcpyW( filename, dirname );
|
|
strcatW( filename, backslashW );
|
|
strcatW( filename, file->name );
|
|
|
|
if (!DeleteFileW( filename )) WARN( "failed to delete file %u\n", GetLastError() );
|
|
HeapFree( GetProcessHeap(), 0, filename );
|
|
}
|
|
RemoveDirectoryW( dirname );
|
|
hr = S_OK;
|
|
|
|
done:
|
|
HeapFree( GetProcessHeap(), 0, dirname );
|
|
HeapFree( GetProcessHeap(), 0, name );
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI cache_UninstallAssembly(
|
|
IAssemblyCache *iface,
|
|
DWORD flags,
|
|
LPCWSTR assembly_name,
|
|
LPCFUSION_INSTALL_REFERENCE ref,
|
|
ULONG *disp )
|
|
{
|
|
struct cache *cache = impl_from_IAssemblyCache( iface );
|
|
HRESULT hr, init;
|
|
IXMLDOMDocument *doc = NULL;
|
|
struct assembly *assembly = NULL;
|
|
IAssemblyName *name_obj = NULL;
|
|
const WCHAR *arch, *name, *token, *type, *version;
|
|
WCHAR *p, *path = NULL;
|
|
|
|
TRACE("%p, 0x%08x, %s, %p, %p\n", iface, flags, debugstr_w(assembly_name), ref, disp);
|
|
|
|
if (ref)
|
|
{
|
|
FIXME("application reference not supported\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
cache_lock( cache );
|
|
init = CoInitialize( NULL );
|
|
|
|
hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, NULL );
|
|
if (FAILED( hr ))
|
|
goto done;
|
|
|
|
arch = get_name_attribute( name_obj, NAME_ATTR_ID_ARCH );
|
|
name = get_name_attribute( name_obj, NAME_ATTR_ID_NAME );
|
|
token = get_name_attribute( name_obj, NAME_ATTR_ID_TOKEN );
|
|
type = get_name_attribute( name_obj, NAME_ATTR_ID_TYPE );
|
|
version = get_name_attribute( name_obj, NAME_ATTR_ID_VERSION );
|
|
if (!arch || !name || !token || !type || !version)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
if (!strcmpW( type, win32W )) path = build_manifest_filename( arch, name, token, version );
|
|
else if (!strcmpW( type, win32_policyW )) path = build_policy_filename( arch, name, token, version );
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
|
|
if (hr != S_OK)
|
|
goto done;
|
|
|
|
if ((hr = load_manifest( doc, path )) != S_OK) goto done;
|
|
if ((hr = parse_assembly( doc, &assembly )) != S_OK) goto done;
|
|
|
|
if (!DeleteFileW( path )) WARN( "unable to remove manifest file %u\n", GetLastError() );
|
|
else if ((p = strrchrW( path, '\\' )))
|
|
{
|
|
*p = 0;
|
|
RemoveDirectoryW( path );
|
|
}
|
|
if (!strcmpW( assembly->type, win32W )) hr = uninstall_assembly( assembly );
|
|
|
|
done:
|
|
if (name_obj) IAssemblyName_Release( name_obj );
|
|
HeapFree( GetProcessHeap(), 0, path );
|
|
free_assembly( assembly );
|
|
if (doc) IXMLDOMDocument_Release( doc );
|
|
if (SUCCEEDED(init)) CoUninitialize();
|
|
cache_unlock( cache );
|
|
return hr;
|
|
}
|
|
|
|
static const IAssemblyCacheVtbl cache_vtbl =
|
|
{
|
|
cache_QueryInterface,
|
|
cache_AddRef,
|
|
cache_Release,
|
|
cache_UninstallAssembly,
|
|
cache_QueryAssemblyInfo,
|
|
cache_CreateAssemblyCacheItem,
|
|
cache_Reserved,
|
|
cache_InstallAssembly
|
|
};
|
|
|
|
/******************************************************************
|
|
* CreateAssemblyCache (SXS.@)
|
|
*/
|
|
HRESULT WINAPI CreateAssemblyCache( IAssemblyCache **obj, DWORD reserved )
|
|
{
|
|
struct cache *cache;
|
|
|
|
TRACE("%p, %u\n", obj, reserved);
|
|
|
|
if (!obj)
|
|
return E_INVALIDARG;
|
|
|
|
*obj = NULL;
|
|
|
|
cache = HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache) );
|
|
if (!cache)
|
|
return E_OUTOFMEMORY;
|
|
|
|
cache->IAssemblyCache_iface.lpVtbl = &cache_vtbl;
|
|
cache->refs = 1;
|
|
cache->lock = CreateMutexW( NULL, FALSE, cache_mutex_nameW );
|
|
if (!cache->lock)
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, cache );
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
*obj = &cache->IAssemblyCache_iface;
|
|
return S_OK;
|
|
}
|