| /* | |
| * 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)) | |
| { | |
| IAssemblyCache_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; | |
| } |