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 IAssemblyCache IAssemblyCache_iface
;
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
,
62 struct cache
*cache
= impl_from_IAssemblyCache(iface
);
64 TRACE("%p, %s, %p\n", cache
, debugstr_guid(riid
), obj
);
68 if (IsEqualIID(riid
, &IID_IUnknown
) ||
69 IsEqualIID(riid
, &IID_IAssemblyCache
))
71 IUnknown_AddRef( iface
);
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
);
92 TRACE("destroying %p\n", cache
);
93 HeapFree( GetProcessHeap(), 0, cache
);
98 static HRESULT WINAPI
cache_UninstallAssembly(
99 IAssemblyCache
*iface
,
102 LPCFUSION_INSTALL_REFERENCE ref
,
105 FIXME("%p, 0x%08x, %s, %p, %p\n", iface
, flags
, debugstr_w(name
), ref
, disp
);
109 static HRESULT WINAPI
cache_QueryAssemblyInfo(
110 IAssemblyCache
*iface
,
113 ASSEMBLY_INFO
*info
)
115 FIXME("%p, 0x%08x, %s, %p\n", iface
, flags
, debugstr_w(name
), info
);
119 static HRESULT WINAPI
cache_CreateAssemblyCacheItem(
120 IAssemblyCache
*iface
,
123 IAssemblyCacheItem
**item
,
126 FIXME("%p, 0x%08x, %p, %p, %s\n", iface
, flags
, reserved
, item
, debugstr_w(name
));
130 static HRESULT WINAPI
cache_Reserved(
131 IAssemblyCache
*iface
,
134 FIXME("%p\n", reserved
);
138 static BSTR
get_attribute_value( IXMLDOMNamedNodeMap
*map
, const WCHAR
*value_name
)
145 str
= SysAllocString( value_name
);
146 hr
= IXMLDOMNamedNodeMap_getNamedItem( map
, str
, &attr
);
147 SysFreeString( str
);
148 if (hr
!= S_OK
) return NULL
;
150 hr
= IXMLDOMNode_get_nodeValue( attr
, &var
);
151 IXMLDOMNode_Release( attr
);
152 if (hr
!= S_OK
) return NULL
;
153 if (V_VT(&var
) != VT_BSTR
)
155 VariantClear( &var
);
158 TRACE("%s=%s\n", debugstr_w(value_name
), debugstr_w(V_BSTR( &var
)));
159 return V_BSTR( &var
);
178 static void free_assembly( struct assembly
*assembly
)
180 struct list
*item
, *cursor
;
182 if (!assembly
) return;
183 SysFreeString( assembly
->type
);
184 SysFreeString( assembly
->name
);
185 SysFreeString( assembly
->version
);
186 SysFreeString( assembly
->arch
);
187 SysFreeString( assembly
->token
);
188 LIST_FOR_EACH_SAFE( item
, cursor
, &assembly
->files
)
190 struct file
*file
= LIST_ENTRY( item
, struct file
, entry
);
191 list_remove( &file
->entry
);
192 SysFreeString( file
->name
);
193 HeapFree( GetProcessHeap(), 0, file
);
195 HeapFree( GetProcessHeap(), 0, assembly
);
198 static HRESULT
parse_files( IXMLDOMDocument
*doc
, struct assembly
*assembly
)
200 static const WCHAR fileW
[] = {'f','i','l','e',0};
201 static const WCHAR nameW
[] = {'n','a','m','e',0};
202 IXMLDOMNamedNodeMap
*attrs
;
203 IXMLDOMNodeList
*list
;
210 str
= SysAllocString( fileW
);
211 hr
= IXMLDOMDocument_getElementsByTagName( doc
, str
, &list
);
212 SysFreeString( str
);
213 if (hr
!= S_OK
) return hr
;
215 hr
= IXMLDOMNodeList_get_length( list
, &len
);
216 if (hr
!= S_OK
) goto done
;
217 TRACE("found %d files\n", len
);
220 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
226 hr
= IXMLDOMNodeList_nextNode( list
, &node
);
227 if (hr
!= S_OK
|| !node
)
233 /* FIXME: validate node type */
235 hr
= IXMLDOMNode_get_attributes( node
, &attrs
);
236 IXMLDOMNode_Release( node
);
240 if (!(f
= HeapAlloc( GetProcessHeap(), 0, sizeof(struct file
) )))
242 IXMLDOMNamedNodeMap_Release( attrs
);
247 f
->name
= get_attribute_value( attrs
, nameW
);
248 IXMLDOMNamedNodeMap_Release( attrs
);
251 HeapFree( GetProcessHeap(), 0, f
);
252 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
255 list_add_tail( &assembly
->files
, &f
->entry
);
258 if (list_empty( &assembly
->files
))
260 WARN("no files found\n");
261 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
265 IXMLDOMNodeList_Release( list
);
269 static HRESULT
parse_assembly( IXMLDOMDocument
*doc
, struct assembly
**assembly
)
271 static const WCHAR identityW
[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
272 static const WCHAR typeW
[] = {'t','y','p','e',0};
273 static const WCHAR nameW
[] = {'n','a','m','e',0};
274 static const WCHAR versionW
[] = {'v','e','r','s','i','o','n',0};
275 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};
276 static const WCHAR tokenW
[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
277 static const WCHAR win32W
[] = {'w','i','n','3','2',0};
278 static const WCHAR policyW
[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
279 IXMLDOMNodeList
*list
= NULL
;
280 IXMLDOMNode
*node
= NULL
;
281 IXMLDOMNamedNodeMap
*attrs
= NULL
;
282 struct assembly
*a
= NULL
;
287 str
= SysAllocString( identityW
);
288 hr
= IXMLDOMDocument_getElementsByTagName( doc
, str
, &list
);
289 SysFreeString( str
);
290 if (hr
!= S_OK
) goto done
;
292 hr
= IXMLDOMNodeList_get_length( list
, &len
);
293 if (hr
!= S_OK
) goto done
;
296 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
299 hr
= IXMLDOMNodeList_nextNode( list
, &node
);
300 if (hr
!= S_OK
) goto done
;
303 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
306 if (!(a
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct assembly
) )))
311 list_init( &a
->files
);
313 hr
= IXMLDOMNode_get_attributes( node
, &attrs
);
314 if (hr
!= S_OK
) goto done
;
316 a
->type
= get_attribute_value( attrs
, typeW
);
317 a
->name
= get_attribute_value( attrs
, nameW
);
318 a
->version
= get_attribute_value( attrs
, versionW
);
319 a
->arch
= get_attribute_value( attrs
, architectureW
);
320 a
->token
= get_attribute_value( attrs
, tokenW
);
322 if (!a
->type
|| (strcmpW( a
->type
, win32W
) && strcmpW( a
->type
, policyW
)) ||
323 !a
->name
|| !a
->version
|| !a
->arch
|| !a
->token
)
325 WARN("invalid win32 assembly\n");
326 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
329 if (!strcmpW( a
->type
, win32W
)) hr
= parse_files( doc
, a
);
332 if (attrs
) IXMLDOMNamedNodeMap_Release( attrs
);
333 if (node
) IXMLDOMNode_Release( node
);
334 if (list
) IXMLDOMNodeList_Release( list
);
335 if (hr
== S_OK
) *assembly
= a
;
336 else free_assembly( a
);
340 static WCHAR
*build_sxs_path( void )
342 static const WCHAR winsxsW
[] = {'\\','w','i','n','s','x','s','\\',0};
343 WCHAR sxsdir
[MAX_PATH
];
345 GetWindowsDirectoryW( sxsdir
, MAX_PATH
);
346 strcatW( sxsdir
, winsxsW
);
347 return strdupW( sxsdir
);
350 static WCHAR
*build_assembly_name( struct assembly
*assembly
)
352 static const WCHAR fmtW
[] =
353 {'%','s','_','%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
357 len
= strlenW( fmtW
);
358 len
+= strlenW( assembly
->arch
);
359 len
+= strlenW( assembly
->name
);
360 len
+= strlenW( assembly
->token
);
361 len
+= strlenW( assembly
->version
);
363 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
364 sprintfW( ret
, fmtW
, assembly
->arch
, assembly
->name
, assembly
->token
, assembly
->version
);
365 for (p
= ret
; *p
; p
++) *p
= tolowerW( *p
);
369 static WCHAR
*build_policy_name( struct assembly
*assembly
)
371 static const WCHAR fmtW
[] =
372 {'%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
376 len
= strlenW( fmtW
);
377 len
+= strlenW( assembly
->arch
);
378 len
+= strlenW( assembly
->name
);
379 len
+= strlenW( assembly
->token
);
381 if (!(ret
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
382 sprintfW( ret
, fmtW
, assembly
->arch
, assembly
->name
, assembly
->token
);
383 for (p
= ret
; *p
; p
++) *p
= tolowerW( *p
);
387 static HRESULT
install_policy( const WCHAR
*manifest
, struct assembly
*assembly
)
389 static const WCHAR policiesW
[] = {'p','o','l','i','c','i','e','s','\\',0};
390 static const WCHAR suffixW
[] = {'.','p','o','l','i','c','y',0};
391 static const WCHAR backslashW
[] = {'\\',0};
392 WCHAR
*sxsdir
, *name
, *dst
;
393 HRESULT hr
= E_OUTOFMEMORY
;
397 /* FIXME: handle catalog file */
399 if (!(sxsdir
= build_sxs_path())) return E_OUTOFMEMORY
;
400 if (!(name
= build_policy_name( assembly
))) goto done
;
402 len
= strlenW( sxsdir
);
403 len
+= strlenW( policiesW
);
404 len
+= strlenW( name
) + 1;
405 len
+= strlenW( assembly
->version
);
406 len
+= strlenW( suffixW
);
408 if (!(dst
= HeapAlloc( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) ))) goto done
;
409 strcpyW( dst
, sxsdir
);
410 strcatW( dst
, policiesW
);
411 CreateDirectoryW( dst
, NULL
);
412 strcatW( dst
, name
);
413 CreateDirectoryW( dst
, NULL
);
414 strcatW( dst
, backslashW
);
415 strcatW( dst
, assembly
->version
);
416 strcatW( dst
, suffixW
);
418 ret
= CopyFileW( manifest
, dst
, FALSE
);
419 HeapFree( GetProcessHeap(), 0, dst
);
422 hr
= HRESULT_FROM_WIN32( GetLastError() );
423 WARN("failed to copy policy manifest file 0x%08x\n", hr
);
428 HeapFree( GetProcessHeap(), 0, sxsdir
);
429 HeapFree( GetProcessHeap(), 0, name
);
433 static WCHAR
*build_source_filename( const WCHAR
*manifest
, struct file
*file
)
439 p
= strrchrW( manifest
, '\\' );
440 if (!p
) p
= strrchrW( manifest
, '/' );
441 if (!p
) return strdupW( manifest
);
443 len
= p
- manifest
+ 1;
444 if (!(src
= HeapAlloc( GetProcessHeap(), 0, (len
+ strlenW( file
->name
) + 1) * sizeof(WCHAR
) )))
447 memcpy( src
, manifest
, len
* sizeof(WCHAR
) );
448 strcpyW( src
+ len
, file
->name
);
452 static HRESULT
install_assembly( const WCHAR
*manifest
, struct assembly
*assembly
)
454 static const WCHAR manifestsW
[] = {'m','a','n','i','f','e','s','t','s','\\',0};
455 static const WCHAR suffixW
[] = {'.','m','a','n','i','f','e','s','t',0};
456 static const WCHAR backslashW
[] = {'\\',0};
457 WCHAR
*sxsdir
, *p
, *name
, *dst
, *src
;
459 HRESULT hr
= E_OUTOFMEMORY
;
463 if (!(sxsdir
= build_sxs_path())) return E_OUTOFMEMORY
;
464 if (!(name
= build_assembly_name( assembly
))) goto done
;
466 len
= strlenW( sxsdir
);
467 len
+= strlenW( manifestsW
);
468 len
+= strlenW( name
);
469 len
+= strlenW( suffixW
);
470 if (!(dst
= HeapAlloc( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) ))) goto done
;
471 strcpyW( dst
, sxsdir
);
472 strcatW( dst
, manifestsW
);
473 strcatW( dst
, name
);
474 strcatW( dst
, suffixW
);
476 ret
= CopyFileW( manifest
, dst
, FALSE
);
477 HeapFree( GetProcessHeap(), 0, dst
);
480 hr
= HRESULT_FROM_WIN32( GetLastError() );
481 WARN("failed to copy manifest file 0x%08x\n", hr
);
485 /* FIXME: this should be a transaction */
486 LIST_FOR_EACH_ENTRY( file
, &assembly
->files
, struct file
, entry
)
488 if (!(src
= build_source_filename( manifest
, file
)))
493 len
= strlenW( sxsdir
) + strlenW( name
) + strlenW( file
->name
);
494 if (!(dst
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2) * sizeof(WCHAR
) )))
496 HeapFree( GetProcessHeap(), 0, src
);
500 strcpyW( dst
, sxsdir
);
501 strcatW( dst
, name
);
502 CreateDirectoryW( dst
, NULL
);
504 strcatW( dst
, backslashW
);
505 strcatW( dst
, file
->name
);
506 for (p
= dst
; *p
; p
++) *p
= tolowerW( *p
);
508 ret
= CopyFileW( src
, dst
, FALSE
);
509 HeapFree( GetProcessHeap(), 0, src
);
510 HeapFree( GetProcessHeap(), 0, dst
);
513 hr
= HRESULT_FROM_WIN32( GetLastError() );
514 WARN("failed to copy file 0x%08x\n", hr
);
521 HeapFree( GetProcessHeap(), 0, sxsdir
);
522 HeapFree( GetProcessHeap(), 0, name
);
526 static HRESULT WINAPI
cache_InstallAssembly(
527 IAssemblyCache
*iface
,
530 LPCFUSION_INSTALL_REFERENCE ref
)
532 static const WCHAR policyW
[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
534 IXMLDOMDocument
*doc
= NULL
;
535 struct assembly
*assembly
= NULL
;
540 TRACE("%p, 0x%08x, %s, %p\n", iface
, flags
, debugstr_w(path
), ref
);
542 init
= CoInitialize( NULL
);
544 hr
= CoCreateInstance( &CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IXMLDOMDocument
, (void **)&doc
);
548 str
= SysAllocString( path
);
550 V_VT( &var
) = VT_BSTR
;
551 V_BSTR( &var
) = str
;
552 hr
= IXMLDOMDocument_load( doc
, var
, &b
);
553 SysFreeString( str
);
554 if (hr
!= S_OK
) goto done
;
557 WARN("failed to load manifest\n");
562 hr
= parse_assembly( doc
, &assembly
);
566 /* FIXME: verify name attributes */
568 if (!strcmpW( assembly
->type
, policyW
))
569 hr
= install_policy( path
, assembly
);
571 hr
= install_assembly( path
, assembly
);
574 free_assembly( assembly
);
575 if (doc
) IXMLDOMDocument_Release( doc
);
583 static const IAssemblyCacheVtbl cache_vtbl
=
585 cache_QueryInterface
,
588 cache_UninstallAssembly
,
589 cache_QueryAssemblyInfo
,
590 cache_CreateAssemblyCacheItem
,
592 cache_InstallAssembly
595 /******************************************************************
596 * CreateAssemblyCache (SXS.@)
598 HRESULT WINAPI
CreateAssemblyCache( IAssemblyCache
**obj
, DWORD reserved
)
602 TRACE("%p, %u\n", obj
, reserved
);
609 cache
= HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache
) );
611 return E_OUTOFMEMORY
;
613 cache
->IAssemblyCache_iface
.lpVtbl
= &cache_vtbl
;
616 *obj
= &cache
->IAssemblyCache_iface
;