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
32 #include "wine/debug.h"
33 #include "wine/list.h"
34 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(sxs);
38 static inline WCHAR *strdupW( const WCHAR *s )
42 if ((t = HeapAlloc( GetProcessHeap(), 0, (strlenW( s ) + 1) * sizeof(WCHAR) ))) strcpyW( t, s );
48 const IAssemblyCacheVtbl *vtbl;
52 static HRESULT WINAPI cache_QueryInterface(
53 IAssemblyCache *iface,
57 struct cache *cache = (struct cache *)iface;
59 TRACE("%p, %s, %p\n", cache, debugstr_guid(riid), obj);
63 if (IsEqualIID(riid, &IID_IUnknown) ||
64 IsEqualIID(riid, &IID_IAssemblyCache))
66 IUnknown_AddRef( iface );
74 static ULONG WINAPI cache_AddRef( IAssemblyCache *iface )
76 struct cache *cache = (struct cache *)iface;
77 return InterlockedIncrement( &cache->refs );
80 static ULONG WINAPI cache_Release( IAssemblyCache *iface )
82 struct cache *cache = (struct cache *)iface;
83 ULONG refs = InterlockedDecrement( &cache->refs );
87 TRACE("destroying %p\n", cache);
88 HeapFree( GetProcessHeap(), 0, cache );
93 static HRESULT WINAPI cache_UninstallAssembly(
94 IAssemblyCache *iface,
97 LPCFUSION_INSTALL_REFERENCE ref,
100 FIXME("%p, 0x%08x, %s, %p, %p\n", iface, flags, debugstr_w(name), ref, disp);
104 static HRESULT WINAPI cache_QueryAssemblyInfo(
105 IAssemblyCache *iface,
108 ASSEMBLY_INFO *info )
110 FIXME("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(name), info);
114 static HRESULT WINAPI cache_CreateAssemblyCacheItem(
115 IAssemblyCache *iface,
118 IAssemblyCacheItem **item,
121 FIXME("%p, 0x%08x, %p, %p, %s\n", iface, flags, reserved, item, debugstr_w(name));
125 static HRESULT WINAPI cache_Reserved(
126 IAssemblyCache *iface,
129 FIXME("%p\n", reserved);
133 static BSTR get_attribute_value( IXMLDOMNamedNodeMap *map, const WCHAR *value_name )
140 str = SysAllocString( value_name );
141 hr = IXMLDOMNamedNodeMap_getNamedItem( map, str, &attr );
142 SysFreeString( str );
143 if (hr != S_OK) return NULL;
145 hr = IXMLDOMNode_get_nodeValue( attr, &var );
146 IXMLDOMNode_Release( attr );
147 if (hr != S_OK) return NULL;
148 if (V_VT(&var) != VT_BSTR)
150 VariantClear( &var );
153 TRACE("%s=%s\n", debugstr_w(value_name), debugstr_w(V_BSTR( &var )));
154 return V_BSTR( &var );
173 static void free_assembly( struct assembly *assembly )
175 struct list *item, *cursor;
177 if (!assembly) return;
178 SysFreeString( assembly->type );
179 SysFreeString( assembly->name );
180 SysFreeString( assembly->version );
181 SysFreeString( assembly->arch );
182 SysFreeString( assembly->token );
183 LIST_FOR_EACH_SAFE( item, cursor, &assembly->files )
185 struct file *file = LIST_ENTRY( item, struct file, entry );
186 list_remove( &file->entry );
187 SysFreeString( file->name );
188 HeapFree( GetProcessHeap(), 0, file );
190 HeapFree( GetProcessHeap(), 0, assembly );
193 static HRESULT parse_files( IXMLDOMDocument *doc, struct assembly *assembly )
195 static const WCHAR fileW[] = {'f','i','l','e',0};
196 static const WCHAR nameW[] = {'n','a','m','e',0};
197 IXMLDOMNamedNodeMap *attrs;
198 IXMLDOMNodeList *list;
205 str = SysAllocString( fileW );
206 hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
207 SysFreeString( str );
208 if (hr != S_OK) return hr;
210 hr = IXMLDOMNodeList_get_length( list, &len );
211 if (hr != S_OK) goto done;
212 TRACE("found %d files\n", len);
215 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
221 hr = IXMLDOMNodeList_nextNode( list, &node );
222 if (hr != S_OK || !node)
228 /* FIXME: validate node type */
230 hr = IXMLDOMNode_get_attributes( node, &attrs );
231 IXMLDOMNode_Release( node );
235 if (!(f = HeapAlloc( GetProcessHeap(), 0, sizeof(struct file) )))
237 IXMLDOMNamedNodeMap_Release( attrs );
242 f->name = get_attribute_value( attrs, nameW );
243 IXMLDOMNamedNodeMap_Release( attrs );
246 HeapFree( GetProcessHeap(), 0, f );
247 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
250 list_add_tail( &assembly->files, &f->entry );
253 if (list_empty( &assembly->files ))
255 WARN("no files found\n");
256 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
260 IXMLDOMNodeList_Release( list );
264 static HRESULT parse_assembly( IXMLDOMDocument *doc, struct assembly **assembly )
266 static const WCHAR identityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
267 static const WCHAR typeW[] = {'t','y','p','e',0};
268 static const WCHAR nameW[] = {'n','a','m','e',0};
269 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
270 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};
271 static const WCHAR tokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
272 static const WCHAR win32W[] = {'w','i','n','3','2',0};
273 static const WCHAR policyW[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
274 IXMLDOMNodeList *list = NULL;
275 IXMLDOMNode *node = NULL;
276 IXMLDOMNamedNodeMap *attrs = NULL;
277 struct assembly *a = NULL;
282 str = SysAllocString( identityW );
283 hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
284 SysFreeString( str );
285 if (hr != S_OK) goto done;
287 hr = IXMLDOMNodeList_get_length( list, &len );
288 if (hr != S_OK) goto done;
291 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
294 hr = IXMLDOMNodeList_nextNode( list, &node );
295 if (hr != S_OK) goto done;
298 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
301 if (!(a = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct assembly) )))
306 list_init( &a->files );
308 hr = IXMLDOMNode_get_attributes( node, &attrs );
309 if (hr != S_OK) goto done;
311 a->type = get_attribute_value( attrs, typeW );
312 a->name = get_attribute_value( attrs, nameW );
313 a->version = get_attribute_value( attrs, versionW );
314 a->arch = get_attribute_value( attrs, architectureW );
315 a->token = get_attribute_value( attrs, tokenW );
317 if (!a->type || (strcmpW( a->type, win32W ) && strcmpW( a->type, policyW )) ||
318 !a->name || !a->version || !a->arch || !a->token)
320 WARN("invalid win32 assembly\n");
321 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
324 if (!strcmpW( a->type, win32W )) hr = parse_files( doc, a );
327 if (attrs) IXMLDOMNamedNodeMap_Release( attrs );
328 if (node) IXMLDOMNode_Release( node );
329 if (list) IXMLDOMNodeList_Release( list );
330 if (hr == S_OK) *assembly = a;
331 else free_assembly( a );
335 static WCHAR *build_sxs_path( void )
337 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\',0};
338 WCHAR sxsdir[MAX_PATH];
340 GetWindowsDirectoryW( sxsdir, MAX_PATH );
341 strcatW( sxsdir, winsxsW );
342 return strdupW( sxsdir );
345 static WCHAR *build_assembly_name( struct assembly *assembly )
347 static const WCHAR fmtW[] =
348 {'%','s','_','%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
352 len = strlenW( fmtW );
353 len += strlenW( assembly->arch );
354 len += strlenW( assembly->name );
355 len += strlenW( assembly->token );
356 len += strlenW( assembly->version );
358 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
359 sprintfW( ret, fmtW, assembly->arch, assembly->name, assembly->token, assembly->version );
360 for (p = ret; *p; p++) *p = tolowerW( *p );
364 static WCHAR *build_policy_name( struct assembly *assembly )
366 static const WCHAR fmtW[] =
367 {'%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
371 len = strlenW( fmtW );
372 len += strlenW( assembly->arch );
373 len += strlenW( assembly->name );
374 len += strlenW( assembly->token );
376 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return NULL;
377 sprintfW( ret, fmtW, assembly->arch, assembly->name, assembly->token );
378 for (p = ret; *p; p++) *p = tolowerW( *p );
382 static HRESULT install_policy( const WCHAR *manifest, struct assembly *assembly )
384 static const WCHAR policiesW[] = {'p','o','l','i','c','i','e','s','\\',0};
385 static const WCHAR suffixW[] = {'.','p','o','l','i','c','y',0};
386 static const WCHAR backslashW[] = {'\\',0};
387 WCHAR *sxsdir, *name, *dst;
388 HRESULT hr = E_OUTOFMEMORY;
392 /* FIXME: handle catalog file */
394 if (!(sxsdir = build_sxs_path())) return E_OUTOFMEMORY;
395 if (!(name = build_policy_name( assembly ))) goto done;
397 len = strlenW( sxsdir );
398 len += strlenW( policiesW );
399 len += strlenW( name ) + 1;
400 len += strlenW( assembly->version );
401 len += strlenW( suffixW );
403 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) goto done;
404 strcpyW( dst, sxsdir );
405 strcatW( dst, policiesW );
406 CreateDirectoryW( dst, NULL );
407 strcatW( dst, name );
408 CreateDirectoryW( dst, NULL );
409 strcatW( dst, backslashW );
410 strcatW( dst, assembly->version );
411 strcatW( dst, suffixW );
413 ret = CopyFileW( manifest, dst, FALSE );
414 HeapFree( GetProcessHeap(), 0, dst );
417 hr = HRESULT_FROM_WIN32( GetLastError() );
418 WARN("failed to copy policy manifest file 0x%08x\n", hr);
423 HeapFree( GetProcessHeap(), 0, sxsdir );
424 HeapFree( GetProcessHeap(), 0, name );
428 static WCHAR *build_source_filename( const WCHAR *manifest, struct file *file )
434 p = strrchrW( manifest, '\\' );
435 if (!p) p = strrchrW( manifest, '/' );
436 if (!p) return strdupW( manifest );
438 len = p - manifest + 1;
439 if (!(src = HeapAlloc( GetProcessHeap(), 0, (len + strlenW( file->name ) + 1) * sizeof(WCHAR) )))
442 memcpy( src, manifest, len * sizeof(WCHAR) );
443 strcpyW( src + len, file->name );
447 static HRESULT install_assembly( const WCHAR *manifest, struct assembly *assembly )
449 static const WCHAR manifestsW[] = {'m','a','n','i','f','e','s','t','s','\\',0};
450 static const WCHAR suffixW[] = {'.','m','a','n','i','f','e','s','t',0};
451 static const WCHAR backslashW[] = {'\\',0};
452 WCHAR *sxsdir, *p, *name, *dst, *src;
454 HRESULT hr = E_OUTOFMEMORY;
458 if (!(sxsdir = build_sxs_path())) return E_OUTOFMEMORY;
459 if (!(name = build_assembly_name( assembly ))) goto done;
461 len = strlenW( sxsdir );
462 len += strlenW( manifestsW );
463 len += strlenW( name );
464 len += strlenW( suffixW );
465 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) goto done;
466 strcpyW( dst, sxsdir );
467 strcatW( dst, manifestsW );
468 strcatW( dst, name );
469 strcatW( dst, suffixW );
471 ret = CopyFileW( manifest, dst, FALSE );
472 HeapFree( GetProcessHeap(), 0, dst );
475 hr = HRESULT_FROM_WIN32( GetLastError() );
476 WARN("failed to copy manifest file 0x%08x\n", hr);
480 /* FIXME: this should be a transaction */
481 LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
483 if (!(src = build_source_filename( manifest, file )))
488 len = strlenW( sxsdir ) + strlenW( name ) + strlenW( file->name );
489 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) )))
491 HeapFree( GetProcessHeap(), 0, src );
495 strcpyW( dst, sxsdir );
496 strcatW( dst, name );
497 CreateDirectoryW( dst, NULL );
499 strcatW( dst, backslashW );
500 strcatW( dst, file->name );
501 for (p = dst; *p; p++) *p = tolowerW( *p );
503 ret = CopyFileW( src, dst, FALSE );
504 HeapFree( GetProcessHeap(), 0, src );
505 HeapFree( GetProcessHeap(), 0, dst );
508 hr = HRESULT_FROM_WIN32( GetLastError() );
509 WARN("failed to copy file 0x%08x\n", hr);
516 HeapFree( GetProcessHeap(), 0, sxsdir );
517 HeapFree( GetProcessHeap(), 0, name );
521 static HRESULT WINAPI cache_InstallAssembly(
522 IAssemblyCache *iface,
525 LPCFUSION_INSTALL_REFERENCE ref )
527 static const WCHAR policyW[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
529 IXMLDOMDocument *doc = NULL;
530 struct assembly *assembly = NULL;
535 TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(path), ref);
537 init = CoInitialize( NULL );
539 hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
543 str = SysAllocString( path );
545 V_VT( &var ) = VT_BSTR;
546 V_BSTR( &var ) = str;
547 hr = IXMLDOMDocument_load( doc, var, &b );
548 SysFreeString( str );
549 if (hr != S_OK) goto done;
552 WARN("failed to load manifest\n");
557 hr = parse_assembly( doc, &assembly );
561 /* FIXME: verify name attributes */
563 if (!strcmpW( assembly->type, policyW ))
564 hr = install_policy( path, assembly );
566 hr = install_assembly( path, assembly );
569 free_assembly( assembly );
570 if (doc) IXMLDOMDocument_Release( doc );
578 static const IAssemblyCacheVtbl cache_vtbl =
580 cache_QueryInterface,
583 cache_UninstallAssembly,
584 cache_QueryAssemblyInfo,
585 cache_CreateAssemblyCacheItem,
587 cache_InstallAssembly
590 /******************************************************************
591 * CreateAssemblyCache (SXS.@)
593 HRESULT WINAPI CreateAssemblyCache( IAssemblyCache **obj, DWORD reserved )
597 TRACE("%p, %u\n", obj, reserved);
604 cache = HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache) );
606 return E_OUTOFMEMORY;
608 cache->vtbl = &cache_vtbl;
611 *obj = (IAssemblyCache *)cache;