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;