Release 1.3.7.
[wine/gsoc-2012-control.git] / dlls / sxs / cache.c
blobcd5f26cb424661566889669e3d28df674fe79337
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"
36 WINE_DEFAULT_DEBUG_CHANNEL(sxs);
38 static inline WCHAR *strdupW( const WCHAR *s )
40 WCHAR *t;
41 if (!s) return NULL;
42 if ((t = HeapAlloc( GetProcessHeap(), 0, (strlenW( s ) + 1) * sizeof(WCHAR) ))) strcpyW( t, s );
43 return t;
46 struct cache
48 const IAssemblyCacheVtbl *vtbl;
49 LONG refs;
52 static HRESULT WINAPI cache_QueryInterface(
53 IAssemblyCache *iface,
54 REFIID riid,
55 void **obj )
57 struct cache *cache = (struct cache *)iface;
59 TRACE("%p, %s, %p\n", cache, debugstr_guid(riid), obj);
61 *obj = NULL;
63 if (IsEqualIID(riid, &IID_IUnknown) ||
64 IsEqualIID(riid, &IID_IAssemblyCache))
66 IUnknown_AddRef( iface );
67 *obj = cache;
68 return S_OK;
71 return E_NOINTERFACE;
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 );
85 if (!refs)
87 TRACE("destroying %p\n", cache);
88 HeapFree( GetProcessHeap(), 0, cache );
90 return refs;
93 static HRESULT WINAPI cache_UninstallAssembly(
94 IAssemblyCache *iface,
95 DWORD flags,
96 LPCWSTR name,
97 LPCFUSION_INSTALL_REFERENCE ref,
98 ULONG *disp )
100 FIXME("%p, 0x%08x, %s, %p, %p\n", iface, flags, debugstr_w(name), ref, disp);
101 return E_NOTIMPL;
104 static HRESULT WINAPI cache_QueryAssemblyInfo(
105 IAssemblyCache *iface,
106 DWORD flags,
107 LPCWSTR name,
108 ASSEMBLY_INFO *info )
110 FIXME("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(name), info);
111 return E_NOTIMPL;
114 static HRESULT WINAPI cache_CreateAssemblyCacheItem(
115 IAssemblyCache *iface,
116 DWORD flags,
117 PVOID reserved,
118 IAssemblyCacheItem **item,
119 LPCWSTR name )
121 FIXME("%p, 0x%08x, %p, %p, %s\n", iface, flags, reserved, item, debugstr_w(name));
122 return E_NOTIMPL;
125 static HRESULT WINAPI cache_Reserved(
126 IAssemblyCache *iface,
127 IUnknown **reserved)
129 FIXME("%p\n", reserved);
130 return E_NOTIMPL;
133 static BSTR get_attribute_value( IXMLDOMNamedNodeMap *map, const WCHAR *value_name )
135 HRESULT hr;
136 IXMLDOMNode *attr;
137 VARIANT var;
138 BSTR str;
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 );
151 return NULL;
153 TRACE("%s=%s\n", debugstr_w(value_name), debugstr_w(V_BSTR( &var )));
154 return V_BSTR( &var );
157 struct file
159 struct list entry;
160 BSTR name;
163 struct assembly
165 BSTR type;
166 BSTR name;
167 BSTR version;
168 BSTR arch;
169 BSTR token;
170 struct list files;
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;
199 IXMLDOMNode *node;
200 struct file *f;
201 BSTR str;
202 HRESULT hr;
203 LONG len;
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);
213 if (!len)
215 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
216 goto done;
219 for (;;)
221 hr = IXMLDOMNodeList_nextNode( list, &node );
222 if (hr != S_OK || !node)
224 hr = S_OK;
225 break;
228 /* FIXME: validate node type */
230 hr = IXMLDOMNode_get_attributes( node, &attrs );
231 IXMLDOMNode_Release( node );
232 if (hr != S_OK)
233 goto done;
235 if (!(f = HeapAlloc( GetProcessHeap(), 0, sizeof(struct file) )))
237 IXMLDOMNamedNodeMap_Release( attrs );
238 hr = E_OUTOFMEMORY;
239 goto done;
242 f->name = get_attribute_value( attrs, nameW );
243 IXMLDOMNamedNodeMap_Release( attrs );
244 if (!f->name)
246 HeapFree( GetProcessHeap(), 0, f );
247 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
248 goto done;
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;
259 done:
260 IXMLDOMNodeList_Release( list );
261 return hr;
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;
278 BSTR str;
279 HRESULT hr;
280 LONG len;
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;
289 if (!len)
291 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
292 goto done;
294 hr = IXMLDOMNodeList_nextNode( list, &node );
295 if (hr != S_OK) goto done;
296 if (!node)
298 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
299 goto done;
301 if (!(a = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct assembly) )))
303 hr = E_OUTOFMEMORY;
304 goto done;
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;
316 goto done;
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;
327 goto done;
330 hr = parse_files( doc, a );
332 done:
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 );
338 return hr;
341 static WCHAR *build_source_filename( const WCHAR *manifest, struct file *file )
343 WCHAR *src;
344 const WCHAR *p;
345 int len;
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) )))
353 return NULL;
355 memcpy( src, manifest, len * sizeof(WCHAR) );
356 strcpyW( src + len, file->name );
357 return src;
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;
369 int len;
370 struct file *file;
371 HRESULT hr = S_OK;
372 BOOL ret;
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 );
405 if (!ret)
407 hr = HRESULT_FROM_WIN32( GetLastError() );
408 WARN("failed to copy manifest file 0x%08x\n", hr);
409 goto done;
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 )))
417 hr = E_OUTOFMEMORY;
418 goto done;
420 len = strlenW( sxsdir ) + strlenW( name ) + strlenW( file->name );
421 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) )))
423 HeapFree( GetProcessHeap(), 0, src );
424 hr = E_OUTOFMEMORY;
425 goto done;
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 );
438 if (!ret)
440 hr = HRESULT_FROM_WIN32( GetLastError() );
441 WARN("failed to copy file 0x%08x\n", hr);
442 goto done;
446 done:
447 HeapFree( GetProcessHeap(), 0, name );
448 return hr;
451 static HRESULT WINAPI cache_InstallAssembly(
452 IAssemblyCache *iface,
453 DWORD flags,
454 LPCWSTR path,
455 LPCFUSION_INSTALL_REFERENCE ref )
457 HRESULT hr, init;
458 IXMLDOMDocument *doc = NULL;
459 struct assembly *assembly = NULL;
460 BSTR str;
461 VARIANT var;
462 VARIANT_BOOL b;
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 );
469 if (hr != S_OK)
470 goto done;
472 str = SysAllocString( path );
473 VariantInit( &var );
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;
479 if (!b)
481 WARN("failed to load manifest\n");
482 hr = S_FALSE;
483 goto done;
486 hr = parse_assembly( doc, &assembly );
487 if (hr != S_OK)
488 goto done;
490 /* FIXME: verify name attributes */
492 hr = install_assembly( path, assembly );
494 done:
495 free_assembly( assembly );
496 if (doc) IXMLDOMDocument_Release( doc );
498 if (SUCCEEDED(init))
499 CoUninitialize();
501 return hr;
504 static const IAssemblyCacheVtbl cache_vtbl =
506 cache_QueryInterface,
507 cache_AddRef,
508 cache_Release,
509 cache_UninstallAssembly,
510 cache_QueryAssemblyInfo,
511 cache_CreateAssemblyCacheItem,
512 cache_Reserved,
513 cache_InstallAssembly
516 /******************************************************************
517 * CreateAssemblyCache (SXS.@)
519 HRESULT WINAPI CreateAssemblyCache( IAssemblyCache **obj, DWORD reserved )
521 struct cache *cache;
523 TRACE("%p, %u\n", obj, reserved);
525 if (!obj)
526 return E_INVALIDARG;
528 *obj = NULL;
530 cache = HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache) );
531 if (!cache)
532 return E_OUTOFMEMORY;
534 cache->vtbl = &cache_vtbl;
535 cache->refs = 1;
537 *obj = (IAssemblyCache *)cache;
538 return S_OK;