libwine: Remove __wine_main_arg* from the public header.
[wine/zf.git] / dlls / sxs / cache.c
blob1b0e1e8908e173ba06336c22fe86e8853c7a0332
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_manifest_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
126 const WCHAR *version )
128 static const WCHAR fmtW[] =
129 {'%','s','m','a','n','i','f','e','s','t','s','\\','%','s','.','m','a','n','i','f','e','s','t',0};
130 WCHAR *path = NULL, *ret, sxsdir[MAX_PATH];
131 unsigned int len;
133 if (!(path = build_assembly_name( arch, name, token, version, &len ))) return NULL;
134 len += ARRAY_SIZE(fmtW);
135 len += build_sxs_path( sxsdir );
136 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
138 HeapFree( GetProcessHeap(), 0, path );
139 return NULL;
141 swprintf( ret, len, fmtW, sxsdir, path );
142 HeapFree( GetProcessHeap(), 0, path );
143 return ret;
146 static WCHAR *build_policy_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
147 unsigned int *len )
149 static const WCHAR fmtW[] =
150 {'%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
151 unsigned int buflen = ARRAY_SIZE(fmtW);
152 WCHAR *ret;
154 buflen += lstrlenW( arch );
155 buflen += lstrlenW( name );
156 buflen += lstrlenW( token );
157 if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL;
158 *len = swprintf( ret, buflen, fmtW, arch, name, token );
159 return wcslwr( ret );
162 static WCHAR *build_policy_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
163 const WCHAR *version )
165 static const WCHAR fmtW[] =
166 {'%','s','p','o','l','i','c','i','e','s','\\','%','s','\\','%','s','.','p','o','l','i','c','y',0};
167 WCHAR *path = NULL, *ret, sxsdir[MAX_PATH];
168 unsigned int len;
170 if (!(path = build_policy_name( arch, name, token, &len ))) return NULL;
171 len += ARRAY_SIZE(fmtW);
172 len += build_sxs_path( sxsdir );
173 len += lstrlenW( version );
174 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
176 HeapFree( GetProcessHeap(), 0, path );
177 return NULL;
179 swprintf( ret, len, fmtW, sxsdir, path, version );
180 HeapFree( GetProcessHeap(), 0, path );
181 return ret;
184 static void cache_lock( struct cache *cache )
186 WaitForSingleObject( cache->lock, INFINITE );
189 static void cache_unlock( struct cache *cache )
191 ReleaseMutex( cache->lock );
194 #define ASSEMBLYINFO_FLAG_INSTALLED 1
196 static HRESULT WINAPI cache_QueryAssemblyInfo(
197 IAssemblyCache *iface,
198 DWORD flags,
199 LPCWSTR assembly_name,
200 ASSEMBLY_INFO *info )
202 struct cache *cache = impl_from_IAssemblyCache( iface );
203 IAssemblyName *name_obj;
204 const WCHAR *arch, *name, *token, *type, *version;
205 WCHAR *p, *path = NULL;
206 unsigned int len;
207 HRESULT hr;
209 TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(assembly_name), info);
211 if (flags || (info && info->cbAssemblyInfo != sizeof(*info)))
212 return E_INVALIDARG;
214 hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, 0 );
215 if (FAILED( hr ))
216 return hr;
218 arch = get_name_attribute( name_obj, NAME_ATTR_ID_ARCH );
219 name = get_name_attribute( name_obj, NAME_ATTR_ID_NAME );
220 token = get_name_attribute( name_obj, NAME_ATTR_ID_TOKEN );
221 type = get_name_attribute( name_obj, NAME_ATTR_ID_TYPE );
222 version = get_name_attribute( name_obj, NAME_ATTR_ID_VERSION );
223 if (!arch || !name || !token || !type || !version)
225 IAssemblyName_Release( name_obj );
226 return HRESULT_FROM_WIN32( ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE );
228 if (!info)
230 IAssemblyName_Release( name_obj );
231 return S_OK;
233 cache_lock( cache );
235 if (!wcscmp( type, win32W )) path = build_manifest_path( arch, name, token, version );
236 else if (!wcscmp( type, win32_policyW )) path = build_policy_path( arch, name, token, version );
237 else
239 hr = HRESULT_FROM_WIN32( ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE );
240 goto done;
242 if (!path)
244 hr = E_OUTOFMEMORY;
245 goto done;
247 hr = S_OK;
248 if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES) /* FIXME: better check */
250 info->dwAssemblyFlags = ASSEMBLYINFO_FLAG_INSTALLED;
251 TRACE("assembly is installed\n");
253 if ((p = wcsrchr( path, '\\' ))) *p = 0;
254 len = lstrlenW( path ) + 1;
255 if (info->pszCurrentAssemblyPathBuf)
257 if (info->cchBuf < len)
259 info->cchBuf = len;
260 hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
262 else lstrcpyW( info->pszCurrentAssemblyPathBuf, path );
265 done:
266 HeapFree( GetProcessHeap(), 0, path );
267 IAssemblyName_Release( name_obj );
268 cache_unlock( cache );
269 return hr;
272 static HRESULT WINAPI cache_CreateAssemblyCacheItem(
273 IAssemblyCache *iface,
274 DWORD flags,
275 PVOID reserved,
276 IAssemblyCacheItem **item,
277 LPCWSTR name )
279 FIXME("%p, 0x%08x, %p, %p, %s\n", iface, flags, reserved, item, debugstr_w(name));
280 return E_NOTIMPL;
283 static HRESULT WINAPI cache_Reserved(
284 IAssemblyCache *iface,
285 IUnknown **reserved)
287 FIXME("%p\n", reserved);
288 return E_NOTIMPL;
291 static BSTR get_attribute_value( IXMLDOMNamedNodeMap *map, const WCHAR *value_name )
293 HRESULT hr;
294 IXMLDOMNode *attr;
295 VARIANT var;
296 BSTR str;
298 str = SysAllocString( value_name );
299 hr = IXMLDOMNamedNodeMap_getNamedItem( map, str, &attr );
300 SysFreeString( str );
301 if (hr != S_OK) return NULL;
303 hr = IXMLDOMNode_get_nodeValue( attr, &var );
304 IXMLDOMNode_Release( attr );
305 if (hr != S_OK) return NULL;
306 if (V_VT(&var) != VT_BSTR)
308 VariantClear( &var );
309 return NULL;
311 TRACE("%s=%s\n", debugstr_w(value_name), debugstr_w(V_BSTR( &var )));
312 return V_BSTR( &var );
315 struct file
317 struct list entry;
318 BSTR name;
321 struct assembly
323 BSTR type;
324 BSTR name;
325 BSTR version;
326 BSTR arch;
327 BSTR token;
328 struct list files;
331 static void free_assembly( struct assembly *assembly )
333 struct list *item, *cursor;
335 if (!assembly) return;
336 SysFreeString( assembly->type );
337 SysFreeString( assembly->name );
338 SysFreeString( assembly->version );
339 SysFreeString( assembly->arch );
340 SysFreeString( assembly->token );
341 LIST_FOR_EACH_SAFE( item, cursor, &assembly->files )
343 struct file *file = LIST_ENTRY( item, struct file, entry );
344 list_remove( &file->entry );
345 SysFreeString( file->name );
346 HeapFree( GetProcessHeap(), 0, file );
348 HeapFree( GetProcessHeap(), 0, assembly );
351 static HRESULT parse_files( IXMLDOMDocument *doc, struct assembly *assembly )
353 static const WCHAR fileW[] = {'f','i','l','e',0};
354 static const WCHAR nameW[] = {'n','a','m','e',0};
355 IXMLDOMNamedNodeMap *attrs;
356 IXMLDOMNodeList *list;
357 IXMLDOMNode *node;
358 struct file *f;
359 BSTR str;
360 HRESULT hr;
361 LONG len;
363 str = SysAllocString( fileW );
364 hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
365 SysFreeString( str );
366 if (hr != S_OK) return hr;
368 hr = IXMLDOMNodeList_get_length( list, &len );
369 if (hr != S_OK) goto done;
370 TRACE("found %d files\n", len);
371 if (!len)
373 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
374 goto done;
377 for (;;)
379 hr = IXMLDOMNodeList_nextNode( list, &node );
380 if (hr != S_OK || !node)
382 hr = S_OK;
383 break;
386 /* FIXME: validate node type */
388 hr = IXMLDOMNode_get_attributes( node, &attrs );
389 IXMLDOMNode_Release( node );
390 if (hr != S_OK)
391 goto done;
393 if (!(f = HeapAlloc( GetProcessHeap(), 0, sizeof(struct file) )))
395 IXMLDOMNamedNodeMap_Release( attrs );
396 hr = E_OUTOFMEMORY;
397 goto done;
400 f->name = get_attribute_value( attrs, nameW );
401 IXMLDOMNamedNodeMap_Release( attrs );
402 if (!f->name)
404 HeapFree( GetProcessHeap(), 0, f );
405 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
406 goto done;
408 list_add_tail( &assembly->files, &f->entry );
411 if (list_empty( &assembly->files ))
413 WARN("no files found\n");
414 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
417 done:
418 IXMLDOMNodeList_Release( list );
419 return hr;
422 static HRESULT parse_assembly( IXMLDOMDocument *doc, struct assembly **assembly )
424 static const WCHAR identityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
425 static const WCHAR typeW[] = {'t','y','p','e',0};
426 static const WCHAR nameW[] = {'n','a','m','e',0};
427 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
428 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};
429 static const WCHAR tokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
430 IXMLDOMNodeList *list = NULL;
431 IXMLDOMNode *node = NULL;
432 IXMLDOMNamedNodeMap *attrs = NULL;
433 struct assembly *a = NULL;
434 BSTR str;
435 HRESULT hr;
436 LONG len;
438 str = SysAllocString( identityW );
439 hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
440 SysFreeString( str );
441 if (hr != S_OK) goto done;
443 hr = IXMLDOMNodeList_get_length( list, &len );
444 if (hr != S_OK) goto done;
445 if (!len)
447 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
448 goto done;
450 hr = IXMLDOMNodeList_nextNode( list, &node );
451 if (hr != S_OK) goto done;
452 if (!node)
454 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
455 goto done;
457 if (!(a = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct assembly) )))
459 hr = E_OUTOFMEMORY;
460 goto done;
462 list_init( &a->files );
464 hr = IXMLDOMNode_get_attributes( node, &attrs );
465 if (hr != S_OK) goto done;
467 a->type = get_attribute_value( attrs, typeW );
468 a->name = get_attribute_value( attrs, nameW );
469 a->version = get_attribute_value( attrs, versionW );
470 a->arch = get_attribute_value( attrs, architectureW );
471 a->token = get_attribute_value( attrs, tokenW );
473 if (!a->type || (wcscmp( a->type, win32W ) && wcscmp( a->type, win32_policyW )) ||
474 !a->name || !a->version || !a->arch || !a->token)
476 WARN("invalid win32 assembly\n");
477 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
478 goto done;
480 if (!wcscmp( a->type, win32W )) hr = parse_files( doc, a );
482 done:
483 if (attrs) IXMLDOMNamedNodeMap_Release( attrs );
484 if (node) IXMLDOMNode_Release( node );
485 if (list) IXMLDOMNodeList_Release( list );
486 if (hr == S_OK) *assembly = a;
487 else free_assembly( a );
488 return hr;
491 static WCHAR *build_policy_filename( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
492 const WCHAR *version )
494 static const WCHAR policiesW[] = {'p','o','l','i','c','i','e','s','\\',0};
495 static const WCHAR suffixW[] = {'.','p','o','l','i','c','y',0};
496 WCHAR sxsdir[MAX_PATH], *ret, *fullname;
497 unsigned int len;
499 if (!(fullname = build_policy_name( arch, name, token, &len ))) return NULL;
500 len += build_sxs_path( sxsdir );
501 len += ARRAY_SIZE(policiesW) - 1;
502 len += lstrlenW( version );
503 len += ARRAY_SIZE(suffixW) - 1;
504 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
506 HeapFree( GetProcessHeap(), 0, fullname );
507 return NULL;
509 lstrcpyW( ret, sxsdir );
510 lstrcatW( ret, policiesW );
511 CreateDirectoryW( ret, NULL );
512 lstrcatW( ret, name );
513 CreateDirectoryW( ret, NULL );
514 lstrcatW( ret, backslashW );
515 lstrcatW( ret, version );
516 lstrcatW( ret, suffixW );
518 HeapFree( GetProcessHeap(), 0, fullname );
519 return ret;
522 static HRESULT install_policy( const WCHAR *manifest, struct assembly *assembly )
524 WCHAR *dst;
525 BOOL ret;
527 /* FIXME: handle catalog file */
529 dst = build_policy_filename( assembly->arch, assembly->name, assembly->token, assembly->version );
530 if (!dst) return E_OUTOFMEMORY;
532 ret = CopyFileW( manifest, dst, FALSE );
533 HeapFree( GetProcessHeap(), 0, dst );
534 if (!ret)
536 HRESULT hr = HRESULT_FROM_WIN32( GetLastError() );
537 WARN("failed to copy policy manifest file 0x%08x\n", hr);
538 return hr;
540 return S_OK;
543 static WCHAR *build_source_filename( const WCHAR *manifest, struct file *file )
545 WCHAR *src;
546 const WCHAR *p;
547 int len;
549 p = wcsrchr( manifest, '\\' );
550 if (!p) p = wcsrchr( manifest, '/' );
551 if (!p) return strdupW( manifest );
553 len = p - manifest + 1;
554 if (!(src = HeapAlloc( GetProcessHeap(), 0, (len + lstrlenW( file->name ) + 1) * sizeof(WCHAR) )))
555 return NULL;
557 memcpy( src, manifest, len * sizeof(WCHAR) );
558 lstrcpyW( src + len, file->name );
559 return src;
562 static WCHAR *build_manifest_filename( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
563 const WCHAR *version )
565 static const WCHAR manifestsW[] = {'m','a','n','i','f','e','s','t','s','\\',0};
566 static const WCHAR suffixW[] = {'.','m','a','n','i','f','e','s','t',0};
567 WCHAR sxsdir[MAX_PATH], *ret, *fullname;
568 unsigned int len;
570 if (!(fullname = build_assembly_name( arch, name, token, version, &len ))) return NULL;
571 len += build_sxs_path( sxsdir );
572 len += ARRAY_SIZE(manifestsW) - 1;
573 len += ARRAY_SIZE(suffixW) - 1;
574 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
576 HeapFree( GetProcessHeap(), 0, fullname );
577 return NULL;
579 lstrcpyW( ret, sxsdir );
580 lstrcatW( ret, manifestsW );
581 lstrcatW( ret, fullname );
582 lstrcatW( ret, suffixW );
584 HeapFree( GetProcessHeap(), 0, fullname );
585 return ret;
588 static HRESULT load_manifest( IXMLDOMDocument *doc, const WCHAR *filename )
590 HRESULT hr;
591 VARIANT var;
592 VARIANT_BOOL b;
593 BSTR str;
595 str = SysAllocString( filename );
596 VariantInit( &var );
597 V_VT( &var ) = VT_BSTR;
598 V_BSTR( &var ) = str;
599 hr = IXMLDOMDocument_load( doc, var, &b );
600 SysFreeString( str );
601 if (hr != S_OK) return hr;
602 if (!b)
604 WARN("failed to load manifest\n");
605 return S_FALSE;
607 return S_OK;
610 static HRESULT install_assembly( const WCHAR *manifest, struct assembly *assembly )
612 WCHAR sxsdir[MAX_PATH], *p, *name, *dst, *src;
613 unsigned int len, len_name, len_sxsdir = build_sxs_path( sxsdir );
614 struct file *file;
615 HRESULT hr = E_OUTOFMEMORY;
616 BOOL ret;
618 dst = build_manifest_filename( assembly->arch, assembly->name, assembly->token, assembly->version );
619 if (!dst) return E_OUTOFMEMORY;
621 ret = CopyFileW( manifest, dst, FALSE );
622 HeapFree( GetProcessHeap(), 0, dst );
623 if (!ret)
625 hr = HRESULT_FROM_WIN32( GetLastError() );
626 WARN("failed to copy manifest file 0x%08x\n", hr);
627 return hr;
630 name = build_assembly_name( assembly->arch, assembly->name, assembly->token, assembly->version,
631 &len_name );
632 if (!name) return E_OUTOFMEMORY;
634 /* FIXME: this should be a transaction */
635 LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
637 if (!(src = build_source_filename( manifest, file ))) goto done;
639 len = len_sxsdir + len_name + lstrlenW( file->name );
640 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) )))
642 HeapFree( GetProcessHeap(), 0, src );
643 goto done;
645 lstrcpyW( dst, sxsdir );
646 lstrcatW( dst, name );
647 CreateDirectoryW( dst, NULL );
649 lstrcatW( dst, backslashW );
650 lstrcatW( dst, file->name );
651 for (p = dst; *p; p++) *p = towlower( *p );
653 ret = CopyFileW( src, dst, FALSE );
654 HeapFree( GetProcessHeap(), 0, src );
655 HeapFree( GetProcessHeap(), 0, dst );
656 if (!ret)
658 hr = HRESULT_FROM_WIN32( GetLastError() );
659 WARN("failed to copy file 0x%08x\n", hr);
660 goto done;
663 hr = S_OK;
665 done:
666 HeapFree( GetProcessHeap(), 0, name );
667 return hr;
670 static HRESULT WINAPI cache_InstallAssembly(
671 IAssemblyCache *iface,
672 DWORD flags,
673 LPCWSTR path,
674 LPCFUSION_INSTALL_REFERENCE ref )
676 struct cache *cache = impl_from_IAssemblyCache( iface );
677 HRESULT hr, init;
678 IXMLDOMDocument *doc = NULL;
679 struct assembly *assembly = NULL;
681 TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(path), ref);
683 cache_lock( cache );
684 init = CoInitialize( NULL );
686 hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
687 if (hr != S_OK)
688 goto done;
690 if ((hr = load_manifest( doc, path )) != S_OK) goto done;
691 if ((hr = parse_assembly( doc, &assembly )) != S_OK) goto done;
693 /* FIXME: verify name attributes */
695 if (!wcscmp( assembly->type, win32_policyW ))
696 hr = install_policy( path, assembly );
697 else
698 hr = install_assembly( path, assembly );
700 done:
701 free_assembly( assembly );
702 if (doc) IXMLDOMDocument_Release( doc );
703 if (SUCCEEDED(init)) CoUninitialize();
704 cache_unlock( cache );
705 return hr;
708 static HRESULT uninstall_assembly( struct assembly *assembly )
710 WCHAR sxsdir[MAX_PATH], *name, *dirname, *filename;
711 unsigned int len, len_name, len_sxsdir = build_sxs_path( sxsdir );
712 HRESULT hr = E_OUTOFMEMORY;
713 struct file *file;
715 name = build_assembly_name( assembly->arch, assembly->name, assembly->token, assembly->version,
716 &len_name );
717 if (!name) return E_OUTOFMEMORY;
718 if (!(dirname = HeapAlloc( GetProcessHeap(), 0, (len_sxsdir + len_name + 1) * sizeof(WCHAR) )))
719 goto done;
720 lstrcpyW( dirname, sxsdir );
721 lstrcpyW( dirname + len_sxsdir, name );
723 LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
725 len = len_sxsdir + len_name + 1 + lstrlenW( file->name );
726 if (!(filename = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) goto done;
727 lstrcpyW( filename, dirname );
728 lstrcatW( filename, backslashW );
729 lstrcatW( filename, file->name );
731 if (!DeleteFileW( filename )) WARN( "failed to delete file %u\n", GetLastError() );
732 HeapFree( GetProcessHeap(), 0, filename );
734 RemoveDirectoryW( dirname );
735 hr = S_OK;
737 done:
738 HeapFree( GetProcessHeap(), 0, dirname );
739 HeapFree( GetProcessHeap(), 0, name );
740 return hr;
743 static HRESULT WINAPI cache_UninstallAssembly(
744 IAssemblyCache *iface,
745 DWORD flags,
746 LPCWSTR assembly_name,
747 LPCFUSION_INSTALL_REFERENCE ref,
748 ULONG *disp )
750 struct cache *cache = impl_from_IAssemblyCache( iface );
751 HRESULT hr, init;
752 IXMLDOMDocument *doc = NULL;
753 struct assembly *assembly = NULL;
754 IAssemblyName *name_obj = NULL;
755 const WCHAR *arch, *name, *token, *type, *version;
756 WCHAR *p, *path = NULL;
758 TRACE("%p, 0x%08x, %s, %p, %p\n", iface, flags, debugstr_w(assembly_name), ref, disp);
760 if (ref)
762 FIXME("application reference not supported\n");
763 return E_NOTIMPL;
765 cache_lock( cache );
766 init = CoInitialize( NULL );
768 hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, NULL );
769 if (FAILED( hr ))
770 goto done;
772 arch = get_name_attribute( name_obj, NAME_ATTR_ID_ARCH );
773 name = get_name_attribute( name_obj, NAME_ATTR_ID_NAME );
774 token = get_name_attribute( name_obj, NAME_ATTR_ID_TOKEN );
775 type = get_name_attribute( name_obj, NAME_ATTR_ID_TYPE );
776 version = get_name_attribute( name_obj, NAME_ATTR_ID_VERSION );
777 if (!arch || !name || !token || !type || !version)
779 hr = E_INVALIDARG;
780 goto done;
782 if (!wcscmp( type, win32W )) path = build_manifest_filename( arch, name, token, version );
783 else if (!wcscmp( type, win32_policyW )) path = build_policy_filename( arch, name, token, version );
784 else
786 hr = E_INVALIDARG;
787 goto done;
790 hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
791 if (hr != S_OK)
792 goto done;
794 if ((hr = load_manifest( doc, path )) != S_OK) goto done;
795 if ((hr = parse_assembly( doc, &assembly )) != S_OK) goto done;
797 if (!DeleteFileW( path )) WARN( "unable to remove manifest file %u\n", GetLastError() );
798 else if ((p = wcsrchr( path, '\\' )))
800 *p = 0;
801 RemoveDirectoryW( path );
803 if (!wcscmp( assembly->type, win32W )) hr = uninstall_assembly( assembly );
805 done:
806 if (name_obj) IAssemblyName_Release( name_obj );
807 HeapFree( GetProcessHeap(), 0, path );
808 free_assembly( assembly );
809 if (doc) IXMLDOMDocument_Release( doc );
810 if (SUCCEEDED(init)) CoUninitialize();
811 cache_unlock( cache );
812 return hr;
815 static const IAssemblyCacheVtbl cache_vtbl =
817 cache_QueryInterface,
818 cache_AddRef,
819 cache_Release,
820 cache_UninstallAssembly,
821 cache_QueryAssemblyInfo,
822 cache_CreateAssemblyCacheItem,
823 cache_Reserved,
824 cache_InstallAssembly
827 /******************************************************************
828 * CreateAssemblyCache (SXS.@)
830 HRESULT WINAPI CreateAssemblyCache( IAssemblyCache **obj, DWORD reserved )
832 struct cache *cache;
834 TRACE("%p, %u\n", obj, reserved);
836 if (!obj)
837 return E_INVALIDARG;
839 *obj = NULL;
841 cache = HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache) );
842 if (!cache)
843 return E_OUTOFMEMORY;
845 cache->IAssemblyCache_iface.lpVtbl = &cache_vtbl;
846 cache->refs = 1;
847 cache->lock = CreateMutexW( NULL, FALSE, cache_mutex_nameW );
848 if (!cache->lock)
850 HeapFree( GetProcessHeap(), 0, cache );
851 return HRESULT_FROM_WIN32( GetLastError() );
853 *obj = &cache->IAssemblyCache_iface;
854 return S_OK;