include/wine/test.h: Fix tests compilation with a PSDK compiler.
[wine/multimedia.git] / dlls / sxs / cache.c
blob02cf455f9b2719d6654fbd09aa9efc44dda2c578
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define INITGUID
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "winsxs.h"
30 #include "msxml2.h"
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};
42 struct cache
44 IAssemblyCache IAssemblyCache_iface;
45 LONG refs;
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,
55 REFIID riid,
56 void **obj )
58 struct cache *cache = impl_from_IAssemblyCache(iface);
60 TRACE("%p, %s, %p\n", cache, debugstr_guid(riid), obj);
62 *obj = NULL;
64 if (IsEqualIID(riid, &IID_IUnknown) ||
65 IsEqualIID(riid, &IID_IAssemblyCache))
67 IUnknown_AddRef( iface );
68 *obj = cache;
69 return S_OK;
72 return E_NOINTERFACE;
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 );
86 if (!refs)
88 TRACE("destroying %p\n", cache);
89 HeapFree( GetProcessHeap(), 0, cache );
91 return refs;
94 static HRESULT WINAPI cache_UninstallAssembly(
95 IAssemblyCache *iface,
96 DWORD flags,
97 LPCWSTR name,
98 LPCFUSION_INSTALL_REFERENCE ref,
99 ULONG *disp )
101 FIXME("%p, 0x%08x, %s, %p, %p\n", iface, flags, debugstr_w(name), ref, disp);
102 return E_NOTIMPL;
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};
117 WCHAR *ret, *p;
118 int len;
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 );
129 return ret;
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};
136 WCHAR *ret, *p;
137 int len;
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 );
147 return ret;
150 #define ASSEMBLYINFO_FLAG_INSTALLED 1
152 static HRESULT WINAPI cache_QueryAssemblyInfo(
153 IAssemblyCache *iface,
154 DWORD flags,
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;
163 unsigned int len;
164 const WCHAR *arch, *name, *token, *type, *version;
165 WCHAR *p, *path = NULL, *full_path = NULL, sxsdir[MAX_PATH];
166 HRESULT hr;
168 TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(assembly_name), info);
170 if (flags || (info && info->cbAssemblyInfo != sizeof(*info)))
171 return E_INVALIDARG;
173 hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, 0 );
174 if (FAILED( hr ))
175 return hr;
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 );
186 if (!info)
188 IAssemblyName_Release( name_obj );
189 return S_OK;
191 hr = E_OUTOFMEMORY;
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 );
210 else
212 hr = HRESULT_FROM_WIN32( ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE );
213 goto done;
215 hr = S_OK;
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)
227 info->cchBuf = len;
228 hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
230 else strcpyW( info->pszCurrentAssemblyPathBuf, full_path );
233 done:
234 HeapFree( GetProcessHeap(), 0, full_path );
235 HeapFree( GetProcessHeap(), 0, path );
236 IAssemblyName_Release( name_obj );
237 return hr;
240 static HRESULT WINAPI cache_CreateAssemblyCacheItem(
241 IAssemblyCache *iface,
242 DWORD flags,
243 PVOID reserved,
244 IAssemblyCacheItem **item,
245 LPCWSTR name )
247 FIXME("%p, 0x%08x, %p, %p, %s\n", iface, flags, reserved, item, debugstr_w(name));
248 return E_NOTIMPL;
251 static HRESULT WINAPI cache_Reserved(
252 IAssemblyCache *iface,
253 IUnknown **reserved)
255 FIXME("%p\n", reserved);
256 return E_NOTIMPL;
259 static BSTR get_attribute_value( IXMLDOMNamedNodeMap *map, const WCHAR *value_name )
261 HRESULT hr;
262 IXMLDOMNode *attr;
263 VARIANT var;
264 BSTR str;
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 );
277 return NULL;
279 TRACE("%s=%s\n", debugstr_w(value_name), debugstr_w(V_BSTR( &var )));
280 return V_BSTR( &var );
283 struct file
285 struct list entry;
286 BSTR name;
289 struct assembly
291 BSTR type;
292 BSTR name;
293 BSTR version;
294 BSTR arch;
295 BSTR token;
296 struct list files;
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;
325 IXMLDOMNode *node;
326 struct file *f;
327 BSTR str;
328 HRESULT hr;
329 LONG len;
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);
339 if (!len)
341 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
342 goto done;
345 for (;;)
347 hr = IXMLDOMNodeList_nextNode( list, &node );
348 if (hr != S_OK || !node)
350 hr = S_OK;
351 break;
354 /* FIXME: validate node type */
356 hr = IXMLDOMNode_get_attributes( node, &attrs );
357 IXMLDOMNode_Release( node );
358 if (hr != S_OK)
359 goto done;
361 if (!(f = HeapAlloc( GetProcessHeap(), 0, sizeof(struct file) )))
363 IXMLDOMNamedNodeMap_Release( attrs );
364 hr = E_OUTOFMEMORY;
365 goto done;
368 f->name = get_attribute_value( attrs, nameW );
369 IXMLDOMNamedNodeMap_Release( attrs );
370 if (!f->name)
372 HeapFree( GetProcessHeap(), 0, f );
373 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
374 goto done;
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;
385 done:
386 IXMLDOMNodeList_Release( list );
387 return hr;
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;
402 BSTR str;
403 HRESULT hr;
404 LONG len;
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;
413 if (!len)
415 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
416 goto done;
418 hr = IXMLDOMNodeList_nextNode( list, &node );
419 if (hr != S_OK) goto done;
420 if (!node)
422 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
423 goto done;
425 if (!(a = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct assembly) )))
427 hr = E_OUTOFMEMORY;
428 goto done;
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;
446 goto done;
448 if (!strcmpW( a->type, win32W )) hr = parse_files( doc, a );
450 done:
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 );
456 return hr;
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;
466 BOOL ret;
467 int len;
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 );
493 if (!ret)
495 hr = HRESULT_FROM_WIN32( GetLastError() );
496 WARN("failed to copy policy manifest file 0x%08x\n", hr);
498 hr = S_OK;
500 done:
501 HeapFree( GetProcessHeap(), 0, name );
502 return hr;
505 static WCHAR *build_source_filename( const WCHAR *manifest, struct file *file )
507 WCHAR *src;
508 const WCHAR *p;
509 int len;
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) )))
517 return NULL;
519 memcpy( src, manifest, len * sizeof(WCHAR) );
520 strcpyW( src + len, file->name );
521 return src;
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;
530 struct file *file;
531 HRESULT hr = E_OUTOFMEMORY;
532 BOOL ret;
533 int len;
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 );
551 if (!ret)
553 hr = HRESULT_FROM_WIN32( GetLastError() );
554 WARN("failed to copy manifest file 0x%08x\n", hr);
555 goto done;
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 )))
563 hr = E_OUTOFMEMORY;
564 goto done;
566 len = strlenW( sxsdir ) + strlenW( name ) + strlenW( file->name );
567 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) )))
569 HeapFree( GetProcessHeap(), 0, src );
570 hr = E_OUTOFMEMORY;
571 goto done;
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 );
584 if (!ret)
586 hr = HRESULT_FROM_WIN32( GetLastError() );
587 WARN("failed to copy file 0x%08x\n", hr);
588 goto done;
591 hr = S_OK;
593 done:
594 HeapFree( GetProcessHeap(), 0, name );
595 return hr;
598 static HRESULT WINAPI cache_InstallAssembly(
599 IAssemblyCache *iface,
600 DWORD flags,
601 LPCWSTR path,
602 LPCFUSION_INSTALL_REFERENCE ref )
604 HRESULT hr, init;
605 IXMLDOMDocument *doc = NULL;
606 struct assembly *assembly = NULL;
607 BSTR str;
608 VARIANT var;
609 VARIANT_BOOL b;
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 );
616 if (hr != S_OK)
617 goto done;
619 str = SysAllocString( path );
620 VariantInit( &var );
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;
626 if (!b)
628 WARN("failed to load manifest\n");
629 hr = S_FALSE;
630 goto done;
633 hr = parse_assembly( doc, &assembly );
634 if (hr != S_OK)
635 goto done;
637 /* FIXME: verify name attributes */
639 if (!strcmpW( assembly->type, win32_policyW ))
640 hr = install_policy( path, assembly );
641 else
642 hr = install_assembly( path, assembly );
644 done:
645 free_assembly( assembly );
646 if (doc) IXMLDOMDocument_Release( doc );
648 if (SUCCEEDED(init))
649 CoUninitialize();
651 return hr;
654 static const IAssemblyCacheVtbl cache_vtbl =
656 cache_QueryInterface,
657 cache_AddRef,
658 cache_Release,
659 cache_UninstallAssembly,
660 cache_QueryAssemblyInfo,
661 cache_CreateAssemblyCacheItem,
662 cache_Reserved,
663 cache_InstallAssembly
666 /******************************************************************
667 * CreateAssemblyCache (SXS.@)
669 HRESULT WINAPI CreateAssemblyCache( IAssemblyCache **obj, DWORD reserved )
671 struct cache *cache;
673 TRACE("%p, %u\n", obj, reserved);
675 if (!obj)
676 return E_INVALIDARG;
678 *obj = NULL;
680 cache = HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache) );
681 if (!cache)
682 return E_OUTOFMEMORY;
684 cache->IAssemblyCache_iface.lpVtbl = &cache_vtbl;
685 cache->refs = 1;
687 *obj = &cache->IAssemblyCache_iface;
688 return S_OK;