mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / sxs / cache.c
blob0acf012032d24b105b5d9df536860e1d42c24c1f
1 /*
2 * IAssemblyCache implementation
4 * Copyright 2010 Hans Leidekker for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define INITGUID
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "winsxs.h"
30 #include "msxml2.h"
32 #include "wine/debug.h"
33 #include "wine/list.h"
34 #include "sxs_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(sxs);
38 static const WCHAR cache_mutex_nameW[] =
39 {'_','_','W','I','N','E','_','S','X','S','_','C','A','C','H','E','_','M','U','T','E','X','_','_',0};
41 static const WCHAR win32W[] = {'w','i','n','3','2',0};
42 static const WCHAR win32_policyW[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
43 static const WCHAR backslashW[] = {'\\',0};
45 struct cache
47 IAssemblyCache IAssemblyCache_iface;
48 LONG refs;
49 HANDLE lock;
52 static inline struct cache *impl_from_IAssemblyCache(IAssemblyCache *iface)
54 return CONTAINING_RECORD(iface, struct cache, IAssemblyCache_iface);
57 static HRESULT WINAPI cache_QueryInterface(
58 IAssemblyCache *iface,
59 REFIID riid,
60 void **obj )
62 struct cache *cache = impl_from_IAssemblyCache(iface);
64 TRACE("%p, %s, %p\n", cache, debugstr_guid(riid), obj);
66 *obj = NULL;
68 if (IsEqualIID(riid, &IID_IUnknown) ||
69 IsEqualIID(riid, &IID_IAssemblyCache))
71 IAssemblyCache_AddRef( iface );
72 *obj = cache;
73 return S_OK;
76 return E_NOINTERFACE;
79 static ULONG WINAPI cache_AddRef( IAssemblyCache *iface )
81 struct cache *cache = impl_from_IAssemblyCache(iface);
82 return InterlockedIncrement( &cache->refs );
85 static ULONG WINAPI cache_Release( IAssemblyCache *iface )
87 struct cache *cache = impl_from_IAssemblyCache(iface);
88 ULONG refs = InterlockedDecrement( &cache->refs );
90 if (!refs)
92 TRACE("destroying %p\n", cache);
93 CloseHandle( cache->lock );
94 HeapFree( GetProcessHeap(), 0, cache );
96 return refs;
99 static unsigned int build_sxs_path( WCHAR *path )
101 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\',0};
102 unsigned int len = GetWindowsDirectoryW( path, MAX_PATH );
104 memcpy( path + len, winsxsW, sizeof(winsxsW) );
105 return len + ARRAY_SIZE(winsxsW) - 1;
108 static WCHAR *build_assembly_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
109 const WCHAR *version, unsigned int *len )
111 static const WCHAR fmtW[] =
112 {'%','s','_','%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
113 unsigned int buflen = ARRAY_SIZE(fmtW);
114 WCHAR *ret;
116 buflen += lstrlenW( arch );
117 buflen += lstrlenW( name );
118 buflen += lstrlenW( token );
119 buflen += lstrlenW( version );
120 if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL;
121 *len = swprintf( ret, buflen, fmtW, arch, name, token, version );
122 return wcslwr( ret );
125 static WCHAR *build_dll_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
126 const WCHAR *version )
128 WCHAR *path = NULL, *ret, sxsdir[MAX_PATH];
129 unsigned int len;
131 if (!(path = build_assembly_name( arch, name, token, version, &len ))) return NULL;
132 len += build_sxs_path( sxsdir ) + 2;
133 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
135 HeapFree( GetProcessHeap(), 0, path );
136 return NULL;
138 lstrcpyW( ret, sxsdir );
139 lstrcatW( ret, path );
140 lstrcatW( ret, L"\\" );
141 HeapFree( GetProcessHeap(), 0, path );
142 return ret;
145 static WCHAR *build_policy_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
146 unsigned int *len )
148 static const WCHAR fmtW[] =
149 {'%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
150 unsigned int buflen = ARRAY_SIZE(fmtW);
151 WCHAR *ret;
153 buflen += lstrlenW( arch );
154 buflen += lstrlenW( name );
155 buflen += lstrlenW( token );
156 if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL;
157 *len = swprintf( ret, buflen, fmtW, arch, name, token );
158 return wcslwr( ret );
161 static WCHAR *build_policy_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
162 const WCHAR *version )
164 static const WCHAR fmtW[] =
165 {'%','s','p','o','l','i','c','i','e','s','\\','%','s','\\','%','s','.','p','o','l','i','c','y',0};
166 WCHAR *path = NULL, *ret, sxsdir[MAX_PATH];
167 unsigned int len;
169 if (!(path = build_policy_name( arch, name, token, &len ))) return NULL;
170 len += ARRAY_SIZE(fmtW);
171 len += build_sxs_path( sxsdir );
172 len += lstrlenW( version );
173 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
175 HeapFree( GetProcessHeap(), 0, path );
176 return NULL;
178 swprintf( ret, len, fmtW, sxsdir, path, version );
179 HeapFree( GetProcessHeap(), 0, path );
180 return ret;
183 static void cache_lock( struct cache *cache )
185 WaitForSingleObject( cache->lock, INFINITE );
188 static void cache_unlock( struct cache *cache )
190 ReleaseMutex( cache->lock );
193 #define ASSEMBLYINFO_FLAG_INSTALLED 1
195 static HRESULT WINAPI cache_QueryAssemblyInfo(
196 IAssemblyCache *iface,
197 DWORD flags,
198 LPCWSTR assembly_name,
199 ASSEMBLY_INFO *info )
201 struct cache *cache = impl_from_IAssemblyCache( iface );
202 IAssemblyName *name_obj;
203 const WCHAR *arch, *name, *token, *type, *version;
204 WCHAR *path = NULL;
205 unsigned int len;
206 HRESULT hr;
208 TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(assembly_name), info);
210 if (flags || (info && info->cbAssemblyInfo != sizeof(*info)))
211 return E_INVALIDARG;
213 hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, 0 );
214 if (FAILED( hr ))
215 return hr;
217 arch = get_name_attribute( name_obj, NAME_ATTR_ID_ARCH );
218 name = get_name_attribute( name_obj, NAME_ATTR_ID_NAME );
219 token = get_name_attribute( name_obj, NAME_ATTR_ID_TOKEN );
220 type = get_name_attribute( name_obj, NAME_ATTR_ID_TYPE );
221 version = get_name_attribute( name_obj, NAME_ATTR_ID_VERSION );
222 if (!arch || !name || !token || !type || !version)
224 IAssemblyName_Release( name_obj );
225 return HRESULT_FROM_WIN32( ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE );
227 if (!info)
229 IAssemblyName_Release( name_obj );
230 return S_OK;
232 cache_lock( cache );
234 if (!wcscmp( type, win32W )) path = build_dll_path( arch, name, token, version );
235 else if (!wcscmp( type, win32_policyW )) path = build_policy_path( arch, name, token, version );
236 else
238 hr = HRESULT_FROM_WIN32( ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE );
239 goto done;
241 if (!path)
243 hr = E_OUTOFMEMORY;
244 goto done;
246 hr = S_OK;
247 if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES) /* FIXME: better check */
249 info->dwAssemblyFlags = ASSEMBLYINFO_FLAG_INSTALLED;
250 TRACE("assembly is installed\n");
252 len = lstrlenW( path ) + 1;
253 if (info->pszCurrentAssemblyPathBuf)
255 if (info->cchBuf < len)
257 info->cchBuf = len;
258 hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
260 else lstrcpyW( info->pszCurrentAssemblyPathBuf, path );
263 done:
264 HeapFree( GetProcessHeap(), 0, path );
265 IAssemblyName_Release( name_obj );
266 cache_unlock( cache );
267 return hr;
270 static HRESULT WINAPI cache_CreateAssemblyCacheItem(
271 IAssemblyCache *iface,
272 DWORD flags,
273 PVOID reserved,
274 IAssemblyCacheItem **item,
275 LPCWSTR name )
277 FIXME("%p, 0x%08x, %p, %p, %s\n", iface, flags, reserved, item, debugstr_w(name));
278 return E_NOTIMPL;
281 static HRESULT WINAPI cache_Reserved(
282 IAssemblyCache *iface,
283 IUnknown **reserved)
285 FIXME("%p\n", reserved);
286 return E_NOTIMPL;
289 static BSTR get_attribute_value( IXMLDOMNamedNodeMap *map, const WCHAR *value_name )
291 HRESULT hr;
292 IXMLDOMNode *attr;
293 VARIANT var;
294 BSTR str;
296 str = SysAllocString( value_name );
297 hr = IXMLDOMNamedNodeMap_getNamedItem( map, str, &attr );
298 SysFreeString( str );
299 if (hr != S_OK) return NULL;
301 hr = IXMLDOMNode_get_nodeValue( attr, &var );
302 IXMLDOMNode_Release( attr );
303 if (hr != S_OK) return NULL;
304 if (V_VT(&var) != VT_BSTR)
306 VariantClear( &var );
307 return NULL;
309 TRACE("%s=%s\n", debugstr_w(value_name), debugstr_w(V_BSTR( &var )));
310 return V_BSTR( &var );
313 struct file
315 struct list entry;
316 BSTR name;
319 struct assembly
321 BSTR type;
322 BSTR name;
323 BSTR version;
324 BSTR arch;
325 BSTR token;
326 struct list files;
329 static void free_assembly( struct assembly *assembly )
331 struct list *item, *cursor;
333 if (!assembly) return;
334 SysFreeString( assembly->type );
335 SysFreeString( assembly->name );
336 SysFreeString( assembly->version );
337 SysFreeString( assembly->arch );
338 SysFreeString( assembly->token );
339 LIST_FOR_EACH_SAFE( item, cursor, &assembly->files )
341 struct file *file = LIST_ENTRY( item, struct file, entry );
342 list_remove( &file->entry );
343 SysFreeString( file->name );
344 HeapFree( GetProcessHeap(), 0, file );
346 HeapFree( GetProcessHeap(), 0, assembly );
349 static HRESULT parse_files( IXMLDOMDocument *doc, struct assembly *assembly )
351 static const WCHAR fileW[] = {'f','i','l','e',0};
352 static const WCHAR nameW[] = {'n','a','m','e',0};
353 IXMLDOMNamedNodeMap *attrs;
354 IXMLDOMNodeList *list;
355 IXMLDOMNode *node;
356 struct file *f;
357 BSTR str;
358 HRESULT hr;
359 LONG len;
361 str = SysAllocString( fileW );
362 hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
363 SysFreeString( str );
364 if (hr != S_OK) return hr;
366 hr = IXMLDOMNodeList_get_length( list, &len );
367 if (hr != S_OK) goto done;
368 TRACE("found %d files\n", len);
369 if (!len)
371 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
372 goto done;
375 for (;;)
377 hr = IXMLDOMNodeList_nextNode( list, &node );
378 if (hr != S_OK || !node)
380 hr = S_OK;
381 break;
384 /* FIXME: validate node type */
386 hr = IXMLDOMNode_get_attributes( node, &attrs );
387 IXMLDOMNode_Release( node );
388 if (hr != S_OK)
389 goto done;
391 if (!(f = HeapAlloc( GetProcessHeap(), 0, sizeof(struct file) )))
393 IXMLDOMNamedNodeMap_Release( attrs );
394 hr = E_OUTOFMEMORY;
395 goto done;
398 f->name = get_attribute_value( attrs, nameW );
399 IXMLDOMNamedNodeMap_Release( attrs );
400 if (!f->name)
402 HeapFree( GetProcessHeap(), 0, f );
403 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
404 goto done;
406 list_add_tail( &assembly->files, &f->entry );
409 if (list_empty( &assembly->files ))
411 WARN("no files found\n");
412 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
415 done:
416 IXMLDOMNodeList_Release( list );
417 return hr;
420 static HRESULT parse_assembly( IXMLDOMDocument *doc, struct assembly **assembly )
422 static const WCHAR identityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
423 static const WCHAR typeW[] = {'t','y','p','e',0};
424 static const WCHAR nameW[] = {'n','a','m','e',0};
425 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
426 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};
427 static const WCHAR tokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
428 IXMLDOMNodeList *list = NULL;
429 IXMLDOMNode *node = NULL;
430 IXMLDOMNamedNodeMap *attrs = NULL;
431 struct assembly *a = NULL;
432 BSTR str;
433 HRESULT hr;
434 LONG len;
436 str = SysAllocString( identityW );
437 hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
438 SysFreeString( str );
439 if (hr != S_OK) goto done;
441 hr = IXMLDOMNodeList_get_length( list, &len );
442 if (hr != S_OK) goto done;
443 if (!len)
445 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
446 goto done;
448 hr = IXMLDOMNodeList_nextNode( list, &node );
449 if (hr != S_OK) goto done;
450 if (!node)
452 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
453 goto done;
455 if (!(a = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct assembly) )))
457 hr = E_OUTOFMEMORY;
458 goto done;
460 list_init( &a->files );
462 hr = IXMLDOMNode_get_attributes( node, &attrs );
463 if (hr != S_OK) goto done;
465 a->type = get_attribute_value( attrs, typeW );
466 a->name = get_attribute_value( attrs, nameW );
467 a->version = get_attribute_value( attrs, versionW );
468 a->arch = get_attribute_value( attrs, architectureW );
469 a->token = get_attribute_value( attrs, tokenW );
471 if (!a->type || (wcscmp( a->type, win32W ) && wcscmp( a->type, win32_policyW )) ||
472 !a->name || !a->version || !a->arch || !a->token)
474 WARN("invalid win32 assembly\n");
475 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
476 goto done;
478 if (!wcscmp( a->type, win32W )) hr = parse_files( doc, a );
480 done:
481 if (attrs) IXMLDOMNamedNodeMap_Release( attrs );
482 if (node) IXMLDOMNode_Release( node );
483 if (list) IXMLDOMNodeList_Release( list );
484 if (hr == S_OK) *assembly = a;
485 else free_assembly( a );
486 return hr;
489 static WCHAR *build_policy_filename( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
490 const WCHAR *version )
492 static const WCHAR policiesW[] = {'p','o','l','i','c','i','e','s','\\',0};
493 static const WCHAR suffixW[] = {'.','p','o','l','i','c','y',0};
494 WCHAR sxsdir[MAX_PATH], *ret, *fullname;
495 unsigned int len;
497 if (!(fullname = build_policy_name( arch, name, token, &len ))) return NULL;
498 len += build_sxs_path( sxsdir );
499 len += ARRAY_SIZE(policiesW) - 1;
500 len += lstrlenW( version );
501 len += ARRAY_SIZE(suffixW) - 1;
502 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
504 HeapFree( GetProcessHeap(), 0, fullname );
505 return NULL;
507 lstrcpyW( ret, sxsdir );
508 lstrcatW( ret, policiesW );
509 CreateDirectoryW( ret, NULL );
510 lstrcatW( ret, name );
511 CreateDirectoryW( ret, NULL );
512 lstrcatW( ret, backslashW );
513 lstrcatW( ret, version );
514 lstrcatW( ret, suffixW );
516 HeapFree( GetProcessHeap(), 0, fullname );
517 return ret;
520 static HRESULT install_policy( const WCHAR *manifest, struct assembly *assembly )
522 WCHAR *dst;
523 BOOL ret;
525 /* FIXME: handle catalog file */
527 dst = build_policy_filename( assembly->arch, assembly->name, assembly->token, assembly->version );
528 if (!dst) return E_OUTOFMEMORY;
530 ret = CopyFileW( manifest, dst, FALSE );
531 HeapFree( GetProcessHeap(), 0, dst );
532 if (!ret)
534 HRESULT hr = HRESULT_FROM_WIN32( GetLastError() );
535 WARN("failed to copy policy manifest file 0x%08x\n", hr);
536 return hr;
538 return S_OK;
541 static WCHAR *build_source_filename( const WCHAR *manifest, struct file *file )
543 WCHAR *src;
544 const WCHAR *p;
545 int len;
547 p = wcsrchr( manifest, '\\' );
548 if (!p) p = wcsrchr( manifest, '/' );
549 if (!p) return strdupW( manifest );
551 len = p - manifest + 1;
552 if (!(src = HeapAlloc( GetProcessHeap(), 0, (len + lstrlenW( file->name ) + 1) * sizeof(WCHAR) )))
553 return NULL;
555 memcpy( src, manifest, len * sizeof(WCHAR) );
556 lstrcpyW( src + len, file->name );
557 return src;
560 static WCHAR *build_manifest_filename( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
561 const WCHAR *version )
563 static const WCHAR manifestsW[] = {'m','a','n','i','f','e','s','t','s','\\',0};
564 static const WCHAR suffixW[] = {'.','m','a','n','i','f','e','s','t',0};
565 WCHAR sxsdir[MAX_PATH], *ret, *fullname;
566 unsigned int len;
568 if (!(fullname = build_assembly_name( arch, name, token, version, &len ))) return NULL;
569 len += build_sxs_path( sxsdir );
570 len += ARRAY_SIZE(manifestsW) - 1;
571 len += ARRAY_SIZE(suffixW) - 1;
572 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
574 HeapFree( GetProcessHeap(), 0, fullname );
575 return NULL;
577 lstrcpyW( ret, sxsdir );
578 lstrcatW( ret, manifestsW );
579 lstrcatW( ret, fullname );
580 lstrcatW( ret, suffixW );
582 HeapFree( GetProcessHeap(), 0, fullname );
583 return ret;
586 static HRESULT load_manifest( IXMLDOMDocument *doc, const WCHAR *filename )
588 HRESULT hr;
589 VARIANT var;
590 VARIANT_BOOL b;
591 BSTR str;
593 str = SysAllocString( filename );
594 VariantInit( &var );
595 V_VT( &var ) = VT_BSTR;
596 V_BSTR( &var ) = str;
597 hr = IXMLDOMDocument_load( doc, var, &b );
598 SysFreeString( str );
599 if (hr != S_OK) return hr;
600 if (!b)
602 WARN("failed to load manifest\n");
603 return S_FALSE;
605 return S_OK;
608 static HRESULT install_assembly( const WCHAR *manifest, struct assembly *assembly )
610 WCHAR sxsdir[MAX_PATH], *p, *name, *dst, *src;
611 unsigned int len, len_name, len_sxsdir = build_sxs_path( sxsdir );
612 struct file *file;
613 HRESULT hr = E_OUTOFMEMORY;
614 BOOL ret;
616 dst = build_manifest_filename( assembly->arch, assembly->name, assembly->token, assembly->version );
617 if (!dst) return E_OUTOFMEMORY;
619 ret = CopyFileW( manifest, dst, FALSE );
620 HeapFree( GetProcessHeap(), 0, dst );
621 if (!ret)
623 hr = HRESULT_FROM_WIN32( GetLastError() );
624 WARN("failed to copy manifest file 0x%08x\n", hr);
625 return hr;
628 name = build_assembly_name( assembly->arch, assembly->name, assembly->token, assembly->version,
629 &len_name );
630 if (!name) return E_OUTOFMEMORY;
632 /* FIXME: this should be a transaction */
633 LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
635 if (!(src = build_source_filename( manifest, file ))) goto done;
637 len = len_sxsdir + len_name + lstrlenW( file->name );
638 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) )))
640 HeapFree( GetProcessHeap(), 0, src );
641 goto done;
643 lstrcpyW( dst, sxsdir );
644 lstrcatW( dst, name );
645 CreateDirectoryW( dst, NULL );
647 lstrcatW( dst, backslashW );
648 lstrcatW( dst, file->name );
649 for (p = dst; *p; p++) *p = towlower( *p );
651 ret = CopyFileW( src, dst, FALSE );
652 HeapFree( GetProcessHeap(), 0, src );
653 HeapFree( GetProcessHeap(), 0, dst );
654 if (!ret)
656 hr = HRESULT_FROM_WIN32( GetLastError() );
657 WARN("failed to copy file 0x%08x\n", hr);
658 goto done;
661 hr = S_OK;
663 done:
664 HeapFree( GetProcessHeap(), 0, name );
665 return hr;
668 static HRESULT WINAPI cache_InstallAssembly(
669 IAssemblyCache *iface,
670 DWORD flags,
671 LPCWSTR path,
672 LPCFUSION_INSTALL_REFERENCE ref )
674 struct cache *cache = impl_from_IAssemblyCache( iface );
675 HRESULT hr, init;
676 IXMLDOMDocument *doc = NULL;
677 struct assembly *assembly = NULL;
679 TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(path), ref);
681 cache_lock( cache );
682 init = CoInitialize( NULL );
684 hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
685 if (hr != S_OK)
686 goto done;
688 if ((hr = load_manifest( doc, path )) != S_OK) goto done;
689 if ((hr = parse_assembly( doc, &assembly )) != S_OK) goto done;
691 /* FIXME: verify name attributes */
693 if (!wcscmp( assembly->type, win32_policyW ))
694 hr = install_policy( path, assembly );
695 else
696 hr = install_assembly( path, assembly );
698 done:
699 free_assembly( assembly );
700 if (doc) IXMLDOMDocument_Release( doc );
701 if (SUCCEEDED(init)) CoUninitialize();
702 cache_unlock( cache );
703 return hr;
706 static HRESULT uninstall_assembly( struct assembly *assembly )
708 WCHAR sxsdir[MAX_PATH], *name, *dirname, *filename;
709 unsigned int len, len_name, len_sxsdir = build_sxs_path( sxsdir );
710 HRESULT hr = E_OUTOFMEMORY;
711 struct file *file;
713 name = build_assembly_name( assembly->arch, assembly->name, assembly->token, assembly->version,
714 &len_name );
715 if (!name) return E_OUTOFMEMORY;
716 if (!(dirname = HeapAlloc( GetProcessHeap(), 0, (len_sxsdir + len_name + 1) * sizeof(WCHAR) )))
717 goto done;
718 lstrcpyW( dirname, sxsdir );
719 lstrcpyW( dirname + len_sxsdir, name );
721 LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
723 len = len_sxsdir + len_name + 1 + lstrlenW( file->name );
724 if (!(filename = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) goto done;
725 lstrcpyW( filename, dirname );
726 lstrcatW( filename, backslashW );
727 lstrcatW( filename, file->name );
729 if (!DeleteFileW( filename )) WARN( "failed to delete file %u\n", GetLastError() );
730 HeapFree( GetProcessHeap(), 0, filename );
732 RemoveDirectoryW( dirname );
733 hr = S_OK;
735 done:
736 HeapFree( GetProcessHeap(), 0, dirname );
737 HeapFree( GetProcessHeap(), 0, name );
738 return hr;
741 static HRESULT WINAPI cache_UninstallAssembly(
742 IAssemblyCache *iface,
743 DWORD flags,
744 LPCWSTR assembly_name,
745 LPCFUSION_INSTALL_REFERENCE ref,
746 ULONG *disp )
748 struct cache *cache = impl_from_IAssemblyCache( iface );
749 HRESULT hr, init;
750 IXMLDOMDocument *doc = NULL;
751 struct assembly *assembly = NULL;
752 IAssemblyName *name_obj = NULL;
753 const WCHAR *arch, *name, *token, *type, *version;
754 WCHAR *p, *path = NULL;
756 TRACE("%p, 0x%08x, %s, %p, %p\n", iface, flags, debugstr_w(assembly_name), ref, disp);
758 if (ref)
760 FIXME("application reference not supported\n");
761 return E_NOTIMPL;
763 cache_lock( cache );
764 init = CoInitialize( NULL );
766 hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, NULL );
767 if (FAILED( hr ))
768 goto done;
770 arch = get_name_attribute( name_obj, NAME_ATTR_ID_ARCH );
771 name = get_name_attribute( name_obj, NAME_ATTR_ID_NAME );
772 token = get_name_attribute( name_obj, NAME_ATTR_ID_TOKEN );
773 type = get_name_attribute( name_obj, NAME_ATTR_ID_TYPE );
774 version = get_name_attribute( name_obj, NAME_ATTR_ID_VERSION );
775 if (!arch || !name || !token || !type || !version)
777 hr = E_INVALIDARG;
778 goto done;
780 if (!wcscmp( type, win32W )) path = build_manifest_filename( arch, name, token, version );
781 else if (!wcscmp( type, win32_policyW )) path = build_policy_filename( arch, name, token, version );
782 else
784 hr = E_INVALIDARG;
785 goto done;
788 hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
789 if (hr != S_OK)
790 goto done;
792 if ((hr = load_manifest( doc, path )) != S_OK) goto done;
793 if ((hr = parse_assembly( doc, &assembly )) != S_OK) goto done;
795 if (!DeleteFileW( path )) WARN( "unable to remove manifest file %u\n", GetLastError() );
796 else if ((p = wcsrchr( path, '\\' )))
798 *p = 0;
799 RemoveDirectoryW( path );
801 if (!wcscmp( assembly->type, win32W )) hr = uninstall_assembly( assembly );
803 done:
804 if (name_obj) IAssemblyName_Release( name_obj );
805 HeapFree( GetProcessHeap(), 0, path );
806 free_assembly( assembly );
807 if (doc) IXMLDOMDocument_Release( doc );
808 if (SUCCEEDED(init)) CoUninitialize();
809 cache_unlock( cache );
810 return hr;
813 static const IAssemblyCacheVtbl cache_vtbl =
815 cache_QueryInterface,
816 cache_AddRef,
817 cache_Release,
818 cache_UninstallAssembly,
819 cache_QueryAssemblyInfo,
820 cache_CreateAssemblyCacheItem,
821 cache_Reserved,
822 cache_InstallAssembly
825 /******************************************************************
826 * CreateAssemblyCache (SXS.@)
828 HRESULT WINAPI CreateAssemblyCache( IAssemblyCache **obj, DWORD reserved )
830 struct cache *cache;
832 TRACE("%p, %u\n", obj, reserved);
834 if (!obj)
835 return E_INVALIDARG;
837 *obj = NULL;
839 cache = HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache) );
840 if (!cache)
841 return E_OUTOFMEMORY;
843 cache->IAssemblyCache_iface.lpVtbl = &cache_vtbl;
844 cache->refs = 1;
845 cache->lock = CreateMutexW( NULL, FALSE, cache_mutex_nameW );
846 if (!cache->lock)
848 HeapFree( GetProcessHeap(), 0, cache );
849 return HRESULT_FROM_WIN32( GetLastError() );
851 *obj = &cache->IAssemblyCache_iface;
852 return S_OK;