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"
35 #include "sxs_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(sxs
);
39 static const WCHAR win32W
[] = {'w','i','n','3','2',0};
40 static const WCHAR win32_policyW
[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
44 IAssemblyCache IAssemblyCache_iface
;
48 static inline struct cache
*impl_from_IAssemblyCache(IAssemblyCache
*iface
)
50 return CONTAINING_RECORD(iface
, struct cache
, IAssemblyCache_iface
);
53 static HRESULT WINAPI
cache_QueryInterface(
54 IAssemblyCache
*iface
,
58 struct cache
*cache
= impl_from_IAssemblyCache(iface
);
60 TRACE("%p, %s, %p\n", cache
, debugstr_guid(riid
), obj
);
64 if (IsEqualIID(riid
, &IID_IUnknown
) ||
65 IsEqualIID(riid
, &IID_IAssemblyCache
))
67 IUnknown_AddRef( iface
);
75 static ULONG WINAPI
cache_AddRef( IAssemblyCache
*iface
)
77 struct cache
*cache
= impl_from_IAssemblyCache(iface
);
78 return InterlockedIncrement( &cache
->refs
);
81 static ULONG WINAPI
cache_Release( IAssemblyCache
*iface
)
83 struct cache
*cache
= impl_from_IAssemblyCache(iface
);
84 ULONG refs
= InterlockedDecrement( &cache
->refs
);
88 TRACE("destroying %p\n", cache
);
89 HeapFree( GetProcessHeap(), 0, cache
);
94 static HRESULT WINAPI
cache_UninstallAssembly(
95 IAssemblyCache
*iface
,
98 LPCFUSION_INSTALL_REFERENCE ref
,
101 FIXME("%p, 0x%08x, %s, %p, %p\n", iface
, flags
, debugstr_w(name
), ref
, disp
);
105 static void build_sxs_path( WCHAR
*path
)
107 static const WCHAR winsxsW
[] = {'\\','w','i','n','s','x','s','\\',0};
108 GetWindowsDirectoryW( path
, MAX_PATH
);
109 strcatW( path
, winsxsW
);
112 static WCHAR
*build_assembly_name( const WCHAR
*arch
, const WCHAR
*name
, const WCHAR
*token
,
113 const WCHAR
*version
)
115 static const WCHAR fmtW
[] =
116 {'%','s','_','%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
120 len
= strlenW( fmtW
);
121 len
+= strlenW( arch
);
122 len
+= strlenW( name
);
123 len
+= strlenW( token
);
124 len
+= strlenW( version
);
126 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
127 sprintfW( ret
, fmtW
, arch
, name
, token
, version
);
128 for (p
= ret
; *p
; p
++) *p
= tolowerW( *p
);
132 static WCHAR
*build_policy_name( const WCHAR
*arch
, const WCHAR
*name
, const WCHAR
*token
)
134 static const WCHAR fmtW
[] =
135 {'%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
139 len
= strlenW( fmtW
);
140 len
+= strlenW( arch
);
141 len
+= strlenW( name
);
142 len
+= strlenW( token
);
144 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
145 sprintfW( ret
, fmtW
, arch
, name
, token
);
146 for (p
= ret
; *p
; p
++) *p
= tolowerW( *p
);
150 #define ASSEMBLYINFO_FLAG_INSTALLED 1
152 static HRESULT WINAPI
cache_QueryAssemblyInfo(
153 IAssemblyCache
*iface
,
155 LPCWSTR assembly_name
,
156 ASSEMBLY_INFO
*info
)
158 static const WCHAR fmt_assemblyW
[] =
159 {'%','s','m','a','n','i','f','e','s','t','s','\\','%','s','.','m','a','n','i','f','e','s','t',0};
160 static const WCHAR fmt_policyW
[] =
161 {'%','s','p','o','l','i','c','i','e','s','\\','%','s','\\','%','s','.','p','o','l','i','c','y',0};
162 LPASSEMBLYNAME name_obj
;
164 const WCHAR
*arch
, *name
, *token
, *type
, *version
;
165 WCHAR
*p
, *path
= NULL
, *full_path
= NULL
, sxsdir
[MAX_PATH
];
168 TRACE("%p, 0x%08x, %s, %p\n", iface
, flags
, debugstr_w(assembly_name
), info
);
170 if (flags
|| (info
&& info
->cbAssemblyInfo
!= sizeof(*info
)))
173 hr
= CreateAssemblyNameObject( &name_obj
, assembly_name
, CANOF_PARSE_DISPLAY_NAME
, 0 );
177 arch
= get_name_attribute( name_obj
, NAME_ATTR_ID_ARCH
);
178 name
= get_name_attribute( name_obj
, NAME_ATTR_ID_NAME
);
179 token
= get_name_attribute( name_obj
, NAME_ATTR_ID_TOKEN
);
180 type
= get_name_attribute( name_obj
, NAME_ATTR_ID_TYPE
);
181 version
= get_name_attribute( name_obj
, NAME_ATTR_ID_VERSION
);
182 if (!arch
|| !name
|| !token
|| !type
|| !version
)
184 return HRESULT_FROM_WIN32( ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE
);
188 IAssemblyName_Release( name_obj
);
192 build_sxs_path( sxsdir
);
193 len
= strlenW( sxsdir
);
194 if (!strcmpW( type
, win32W
))
196 len
+= strlenW( fmt_assemblyW
);
197 if (!(path
= build_assembly_name( arch
, name
, token
, version
))) goto done
;
198 len
+= strlenW( path
);
199 if (!(full_path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) goto done
;
200 sprintfW( full_path
, fmt_assemblyW
, sxsdir
, path
);
202 else if (!strcmpW( type
, win32_policyW
))
204 len
+= strlenW( fmt_policyW
);
205 if (!(path
= build_policy_name( arch
, name
, token
))) goto done
;
206 len
+= strlenW( path
) + strlenW( version
);
207 if (!(full_path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) goto done
;
208 sprintfW( full_path
, fmt_policyW
, sxsdir
, path
, version
);
212 hr
= HRESULT_FROM_WIN32( ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE
);
216 if (GetFileAttributesW( full_path
) != INVALID_FILE_ATTRIBUTES
) /* FIXME: better check */
218 info
->dwAssemblyFlags
= ASSEMBLYINFO_FLAG_INSTALLED
;
219 TRACE("assembly is installed\n");
221 if ((p
= strrchrW( full_path
, '\\' ))) *p
= 0;
222 len
= strlenW( full_path
) + 1;
223 if (info
->pszCurrentAssemblyPathBuf
)
225 if (info
->cchBuf
< len
)
228 hr
= HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER
);
230 else strcpyW( info
->pszCurrentAssemblyPathBuf
, full_path
);
234 HeapFree( GetProcessHeap(), 0, full_path
);
235 HeapFree( GetProcessHeap(), 0, path
);
236 IAssemblyName_Release( name_obj
);
240 static HRESULT WINAPI
cache_CreateAssemblyCacheItem(
241 IAssemblyCache
*iface
,
244 IAssemblyCacheItem
**item
,
247 FIXME("%p, 0x%08x, %p, %p, %s\n", iface
, flags
, reserved
, item
, debugstr_w(name
));
251 static HRESULT WINAPI
cache_Reserved(
252 IAssemblyCache
*iface
,
255 FIXME("%p\n", reserved
);
259 static BSTR
get_attribute_value( IXMLDOMNamedNodeMap
*map
, const WCHAR
*value_name
)
266 str
= SysAllocString( value_name
);
267 hr
= IXMLDOMNamedNodeMap_getNamedItem( map
, str
, &attr
);
268 SysFreeString( str
);
269 if (hr
!= S_OK
) return NULL
;
271 hr
= IXMLDOMNode_get_nodeValue( attr
, &var
);
272 IXMLDOMNode_Release( attr
);
273 if (hr
!= S_OK
) return NULL
;
274 if (V_VT(&var
) != VT_BSTR
)
276 VariantClear( &var
);
279 TRACE("%s=%s\n", debugstr_w(value_name
), debugstr_w(V_BSTR( &var
)));
280 return V_BSTR( &var
);
299 static void free_assembly( struct assembly
*assembly
)
301 struct list
*item
, *cursor
;
303 if (!assembly
) return;
304 SysFreeString( assembly
->type
);
305 SysFreeString( assembly
->name
);
306 SysFreeString( assembly
->version
);
307 SysFreeString( assembly
->arch
);
308 SysFreeString( assembly
->token
);
309 LIST_FOR_EACH_SAFE( item
, cursor
, &assembly
->files
)
311 struct file
*file
= LIST_ENTRY( item
, struct file
, entry
);
312 list_remove( &file
->entry
);
313 SysFreeString( file
->name
);
314 HeapFree( GetProcessHeap(), 0, file
);
316 HeapFree( GetProcessHeap(), 0, assembly
);
319 static HRESULT
parse_files( IXMLDOMDocument
*doc
, struct assembly
*assembly
)
321 static const WCHAR fileW
[] = {'f','i','l','e',0};
322 static const WCHAR nameW
[] = {'n','a','m','e',0};
323 IXMLDOMNamedNodeMap
*attrs
;
324 IXMLDOMNodeList
*list
;
331 str
= SysAllocString( fileW
);
332 hr
= IXMLDOMDocument_getElementsByTagName( doc
, str
, &list
);
333 SysFreeString( str
);
334 if (hr
!= S_OK
) return hr
;
336 hr
= IXMLDOMNodeList_get_length( list
, &len
);
337 if (hr
!= S_OK
) goto done
;
338 TRACE("found %d files\n", len
);
341 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
347 hr
= IXMLDOMNodeList_nextNode( list
, &node
);
348 if (hr
!= S_OK
|| !node
)
354 /* FIXME: validate node type */
356 hr
= IXMLDOMNode_get_attributes( node
, &attrs
);
357 IXMLDOMNode_Release( node
);
361 if (!(f
= HeapAlloc( GetProcessHeap(), 0, sizeof(struct file
) )))
363 IXMLDOMNamedNodeMap_Release( attrs
);
368 f
->name
= get_attribute_value( attrs
, nameW
);
369 IXMLDOMNamedNodeMap_Release( attrs
);
372 HeapFree( GetProcessHeap(), 0, f
);
373 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
376 list_add_tail( &assembly
->files
, &f
->entry
);
379 if (list_empty( &assembly
->files
))
381 WARN("no files found\n");
382 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
386 IXMLDOMNodeList_Release( list
);
390 static HRESULT
parse_assembly( IXMLDOMDocument
*doc
, struct assembly
**assembly
)
392 static const WCHAR identityW
[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
393 static const WCHAR typeW
[] = {'t','y','p','e',0};
394 static const WCHAR nameW
[] = {'n','a','m','e',0};
395 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
396 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};
397 static const WCHAR tokenW
[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
398 IXMLDOMNodeList
*list
= NULL
;
399 IXMLDOMNode
*node
= NULL
;
400 IXMLDOMNamedNodeMap
*attrs
= NULL
;
401 struct assembly
*a
= NULL
;
406 str
= SysAllocString( identityW
);
407 hr
= IXMLDOMDocument_getElementsByTagName( doc
, str
, &list
);
408 SysFreeString( str
);
409 if (hr
!= S_OK
) goto done
;
411 hr
= IXMLDOMNodeList_get_length( list
, &len
);
412 if (hr
!= S_OK
) goto done
;
415 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
418 hr
= IXMLDOMNodeList_nextNode( list
, &node
);
419 if (hr
!= S_OK
) goto done
;
422 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
425 if (!(a
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct assembly
) )))
430 list_init( &a
->files
);
432 hr
= IXMLDOMNode_get_attributes( node
, &attrs
);
433 if (hr
!= S_OK
) goto done
;
435 a
->type
= get_attribute_value( attrs
, typeW
);
436 a
->name
= get_attribute_value( attrs
, nameW
);
437 a
->version
= get_attribute_value( attrs
, versionW
);
438 a
->arch
= get_attribute_value( attrs
, architectureW
);
439 a
->token
= get_attribute_value( attrs
, tokenW
);
441 if (!a
->type
|| (strcmpW( a
->type
, win32W
) && strcmpW( a
->type
, win32_policyW
)) ||
442 !a
->name
|| !a
->version
|| !a
->arch
|| !a
->token
)
444 WARN("invalid win32 assembly\n");
445 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
448 if (!strcmpW( a
->type
, win32W
)) hr
= parse_files( doc
, a
);
451 if (attrs
) IXMLDOMNamedNodeMap_Release( attrs
);
452 if (node
) IXMLDOMNode_Release( node
);
453 if (list
) IXMLDOMNodeList_Release( list
);
454 if (hr
== S_OK
) *assembly
= a
;
455 else free_assembly( a
);
459 static HRESULT
install_policy( const WCHAR
*manifest
, struct assembly
*assembly
)
461 static const WCHAR policiesW
[] = {'p','o','l','i','c','i','e','s','\\',0};
462 static const WCHAR suffixW
[] = {'.','p','o','l','i','c','y',0};
463 static const WCHAR backslashW
[] = {'\\',0};
464 WCHAR sxsdir
[MAX_PATH
], *name
, *dst
;
465 HRESULT hr
= E_OUTOFMEMORY
;
469 /* FIXME: handle catalog file */
471 build_sxs_path( sxsdir
);
472 name
= build_policy_name( assembly
->arch
, assembly
->name
, assembly
->token
);
473 if (!name
) goto done
;
475 len
= strlenW( sxsdir
);
476 len
+= strlenW( policiesW
);
477 len
+= strlenW( name
) + 1;
478 len
+= strlenW( assembly
->version
);
479 len
+= strlenW( suffixW
);
481 if (!(dst
= HeapAlloc( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) ))) goto done
;
482 strcpyW( dst
, sxsdir
);
483 strcatW( dst
, policiesW
);
484 CreateDirectoryW( dst
, NULL
);
485 strcatW( dst
, name
);
486 CreateDirectoryW( dst
, NULL
);
487 strcatW( dst
, backslashW
);
488 strcatW( dst
, assembly
->version
);
489 strcatW( dst
, suffixW
);
491 ret
= CopyFileW( manifest
, dst
, FALSE
);
492 HeapFree( GetProcessHeap(), 0, dst
);
495 hr
= HRESULT_FROM_WIN32( GetLastError() );
496 WARN("failed to copy policy manifest file 0x%08x\n", hr
);
501 HeapFree( GetProcessHeap(), 0, name
);
505 static WCHAR
*build_source_filename( const WCHAR
*manifest
, struct file
*file
)
511 p
= strrchrW( manifest
, '\\' );
512 if (!p
) p
= strrchrW( manifest
, '/' );
513 if (!p
) return strdupW( manifest
);
515 len
= p
- manifest
+ 1;
516 if (!(src
= HeapAlloc( GetProcessHeap(), 0, (len
+ strlenW( file
->name
) + 1) * sizeof(WCHAR
) )))
519 memcpy( src
, manifest
, len
* sizeof(WCHAR
) );
520 strcpyW( src
+ len
, file
->name
);
524 static HRESULT
install_assembly( const WCHAR
*manifest
, struct assembly
*assembly
)
526 static const WCHAR manifestsW
[] = {'m','a','n','i','f','e','s','t','s','\\',0};
527 static const WCHAR suffixW
[] = {'.','m','a','n','i','f','e','s','t',0};
528 static const WCHAR backslashW
[] = {'\\',0};
529 WCHAR sxsdir
[MAX_PATH
], *p
, *name
, *dst
, *src
;
531 HRESULT hr
= E_OUTOFMEMORY
;
535 build_sxs_path( sxsdir
);
536 name
= build_assembly_name( assembly
->arch
, assembly
->name
, assembly
->token
, assembly
->version
);
537 if (!name
) goto done
;
539 len
= strlenW( sxsdir
);
540 len
+= strlenW( manifestsW
);
541 len
+= strlenW( name
);
542 len
+= strlenW( suffixW
);
543 if (!(dst
= HeapAlloc( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) ))) goto done
;
544 strcpyW( dst
, sxsdir
);
545 strcatW( dst
, manifestsW
);
546 strcatW( dst
, name
);
547 strcatW( dst
, suffixW
);
549 ret
= CopyFileW( manifest
, dst
, FALSE
);
550 HeapFree( GetProcessHeap(), 0, dst
);
553 hr
= HRESULT_FROM_WIN32( GetLastError() );
554 WARN("failed to copy manifest file 0x%08x\n", hr
);
558 /* FIXME: this should be a transaction */
559 LIST_FOR_EACH_ENTRY( file
, &assembly
->files
, struct file
, entry
)
561 if (!(src
= build_source_filename( manifest
, file
)))
566 len
= strlenW( sxsdir
) + strlenW( name
) + strlenW( file
->name
);
567 if (!(dst
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2) * sizeof(WCHAR
) )))
569 HeapFree( GetProcessHeap(), 0, src
);
573 strcpyW( dst
, sxsdir
);
574 strcatW( dst
, name
);
575 CreateDirectoryW( dst
, NULL
);
577 strcatW( dst
, backslashW
);
578 strcatW( dst
, file
->name
);
579 for (p
= dst
; *p
; p
++) *p
= tolowerW( *p
);
581 ret
= CopyFileW( src
, dst
, FALSE
);
582 HeapFree( GetProcessHeap(), 0, src
);
583 HeapFree( GetProcessHeap(), 0, dst
);
586 hr
= HRESULT_FROM_WIN32( GetLastError() );
587 WARN("failed to copy file 0x%08x\n", hr
);
594 HeapFree( GetProcessHeap(), 0, name
);
598 static HRESULT WINAPI
cache_InstallAssembly(
599 IAssemblyCache
*iface
,
602 LPCFUSION_INSTALL_REFERENCE ref
)
605 IXMLDOMDocument
*doc
= NULL
;
606 struct assembly
*assembly
= NULL
;
611 TRACE("%p, 0x%08x, %s, %p\n", iface
, flags
, debugstr_w(path
), ref
);
613 init
= CoInitialize( NULL
);
615 hr
= CoCreateInstance( &CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IXMLDOMDocument
, (void **)&doc
);
619 str
= SysAllocString( path
);
621 V_VT( &var
) = VT_BSTR
;
622 V_BSTR( &var
) = str
;
623 hr
= IXMLDOMDocument_load( doc
, var
, &b
);
624 SysFreeString( str
);
625 if (hr
!= S_OK
) goto done
;
628 WARN("failed to load manifest\n");
633 hr
= parse_assembly( doc
, &assembly
);
637 /* FIXME: verify name attributes */
639 if (!strcmpW( assembly
->type
, win32_policyW
))
640 hr
= install_policy( path
, assembly
);
642 hr
= install_assembly( path
, assembly
);
645 free_assembly( assembly
);
646 if (doc
) IXMLDOMDocument_Release( doc
);
654 static const IAssemblyCacheVtbl cache_vtbl
=
656 cache_QueryInterface
,
659 cache_UninstallAssembly
,
660 cache_QueryAssemblyInfo
,
661 cache_CreateAssemblyCacheItem
,
663 cache_InstallAssembly
666 /******************************************************************
667 * CreateAssemblyCache (SXS.@)
669 HRESULT WINAPI
CreateAssemblyCache( IAssemblyCache
**obj
, DWORD reserved
)
673 TRACE("%p, %u\n", obj
, reserved
);
680 cache
= HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache
) );
682 return E_OUTOFMEMORY
;
684 cache
->IAssemblyCache_iface
.lpVtbl
= &cache_vtbl
;
687 *obj
= &cache
->IAssemblyCache_iface
;