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 if (a
->type
&& !strcmpW( a
->type
, policyW
))
314 FIXME("ignoring policy assembly\n");
315 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
318 a
->name
= get_attribute_value( attrs
, nameW
);
319 a
->version
= get_attribute_value( attrs
, versionW
);
320 a
->arch
= get_attribute_value( attrs
, architectureW
);
321 a
->token
= get_attribute_value( attrs
, tokenW
);
323 if (!a
->type
|| strcmpW( a
->type
, win32W
) || !a
->name
|| !a
->version
|| !a
->arch
|| !a
->token
)
325 WARN("invalid win32 assembly\n");
326 hr
= ERROR_SXS_MANIFEST_FORMAT_ERROR
;
330 hr
= parse_files( doc
, a
);
333 if (attrs
) IXMLDOMNamedNodeMap_Release( attrs
);
334 if (node
) IXMLDOMNode_Release( node
);
335 if (list
) IXMLDOMNodeList_Release( list
);
336 if (hr
== S_OK
) *assembly
= a
;
337 else free_assembly( a
);
341 static WCHAR
*build_source_filename( const WCHAR
*manifest
, struct file
*file
)
347 p
= strrchrW( manifest
, '\\' );
348 if (!p
) p
= strrchrW( manifest
, '/' );
349 if (!p
) return strdupW( manifest
);
351 len
= p
- manifest
+ 1;
352 if (!(src
= HeapAlloc( GetProcessHeap(), 0, (len
+ strlenW( file
->name
) + 1) * sizeof(WCHAR
) )))
355 memcpy( src
, manifest
, len
* sizeof(WCHAR
) );
356 strcpyW( src
+ len
, file
->name
);
360 static HRESULT
install_assembly( const WCHAR
*manifest
, struct assembly
*assembly
)
362 static const WCHAR winsxsW
[] = {'\\','w','i','n','s','x','s','\\',0};
363 static const WCHAR manifestsW
[] = {'m','a','n','i','f','e','s','t','s','\\',0};
364 static const WCHAR deadbeefW
[] = {'n','o','n','e','_','d','e','a','d','b','e','e','f',0};
365 static const WCHAR suffixW
[] = {'.','m','a','n','i','f','e','s','t',0};
366 static const WCHAR backslashW
[] = {'\\',0};
367 static const WCHAR fmtW
[] = {'%','s','_','%','s','_','%','s','_','%','s','_','%','s',0};
368 WCHAR sxsdir
[MAX_PATH
], *p
, *name
, *dst
, *src
;
374 GetWindowsDirectoryW( sxsdir
, MAX_PATH
);
375 strcatW( sxsdir
, winsxsW
);
377 len
= strlenW( fmtW
);
378 len
+= strlenW( assembly
->arch
);
379 len
+= strlenW( assembly
->name
);
380 len
+= strlenW( assembly
->token
);
381 len
+= strlenW( assembly
->version
);
382 len
+= strlenW( deadbeefW
);
384 if (!(name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
385 return E_OUTOFMEMORY
;
387 len
= sprintfW( name
, fmtW
, assembly
->arch
, assembly
->name
, assembly
->token
, assembly
->version
, deadbeefW
);
388 for (p
= name
; *p
; p
++) *p
= tolowerW( *p
);
390 len
+= strlenW( sxsdir
);
391 len
+= strlenW( manifestsW
);
392 len
+= strlenW( suffixW
);
393 if (!(dst
= HeapAlloc( GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
) )))
395 HeapFree( GetProcessHeap(), 0, name
);
396 return E_OUTOFMEMORY
;
398 strcpyW( dst
, sxsdir
);
399 strcatW( dst
, manifestsW
);
400 strcatW( dst
, name
);
401 strcatW( dst
, suffixW
);
403 ret
= CopyFileW( manifest
, dst
, FALSE
);
404 HeapFree( GetProcessHeap(), 0, dst
);
407 hr
= HRESULT_FROM_WIN32( GetLastError() );
408 WARN("failed to copy manifest file 0x%08x\n", hr
);
412 /* FIXME: this should be a transaction */
413 LIST_FOR_EACH_ENTRY( file
, &assembly
->files
, struct file
, entry
)
415 if (!(src
= build_source_filename( manifest
, file
)))
420 len
= strlenW( sxsdir
) + strlenW( name
) + strlenW( file
->name
);
421 if (!(dst
= HeapAlloc( GetProcessHeap(), 0, (len
+ 2) * sizeof(WCHAR
) )))
423 HeapFree( GetProcessHeap(), 0, src
);
427 strcpyW( dst
, sxsdir
);
428 strcatW( dst
, name
);
429 CreateDirectoryW( dst
, NULL
);
431 strcatW( dst
, backslashW
);
432 strcatW( dst
, file
->name
);
433 for (p
= dst
; *p
; p
++) *p
= tolowerW( *p
);
435 ret
= CopyFileW( src
, dst
, FALSE
);
436 HeapFree( GetProcessHeap(), 0, src
);
437 HeapFree( GetProcessHeap(), 0, dst
);
440 hr
= HRESULT_FROM_WIN32( GetLastError() );
441 WARN("failed to copy file 0x%08x\n", hr
);
447 HeapFree( GetProcessHeap(), 0, name
);
451 static HRESULT WINAPI
cache_InstallAssembly(
452 IAssemblyCache
*iface
,
455 LPCFUSION_INSTALL_REFERENCE ref
)
458 IXMLDOMDocument
*doc
= NULL
;
459 struct assembly
*assembly
= NULL
;
464 TRACE("%p, 0x%08x, %s, %p\n", iface
, flags
, debugstr_w(path
), ref
);
466 init
= CoInitialize( NULL
);
468 hr
= CoCreateInstance( &CLSID_DOMDocument
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IXMLDOMDocument
, (void **)&doc
);
472 str
= SysAllocString( path
);
474 V_VT( &var
) = VT_BSTR
;
475 V_BSTR( &var
) = str
;
476 hr
= IXMLDOMDocument_load( doc
, var
, &b
);
477 SysFreeString( str
);
478 if (hr
!= S_OK
) goto done
;
481 WARN("failed to load manifest\n");
486 hr
= parse_assembly( doc
, &assembly
);
490 /* FIXME: verify name attributes */
492 hr
= install_assembly( path
, assembly
);
495 free_assembly( assembly
);
496 if (doc
) IXMLDOMDocument_Release( doc
);
504 static const IAssemblyCacheVtbl cache_vtbl
=
506 cache_QueryInterface
,
509 cache_UninstallAssembly
,
510 cache_QueryAssemblyInfo
,
511 cache_CreateAssemblyCacheItem
,
513 cache_InstallAssembly
516 /******************************************************************
517 * CreateAssemblyCache (SXS.@)
519 HRESULT WINAPI
CreateAssemblyCache( IAssemblyCache
**obj
, DWORD reserved
)
523 TRACE("%p, %u\n", obj
, reserved
);
530 cache
= HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache
) );
532 return E_OUTOFMEMORY
;
534 cache
->vtbl
= &cache_vtbl
;
537 *obj
= (IAssemblyCache
*)cache
;