Synchronize with trunk's revision r57652.
[reactos.git] / dll / win32 / sxs / cache.c
1 /*
2 * IAssemblyCache implementation
3 *
4 * Copyright 2010 Hans Leidekker for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define INITGUID
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "winsxs.h"
30 #include "msxml2.h"
31
32 #include "wine/debug.h"
33 #include "wine/list.h"
34 #include "wine/unicode.h"
35 #include "sxs_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(sxs);
38
39 static const WCHAR cache_mutex_nameW[] =
40 {'_','_','W','I','N','E','_','S','X','S','_','C','A','C','H','E','_','M','U','T','E','X','_','_',0};
41
42 static const WCHAR win32W[] = {'w','i','n','3','2',0};
43 static const WCHAR win32_policyW[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
44 static const WCHAR backslashW[] = {'\\',0};
45
46 struct cache
47 {
48 IAssemblyCache IAssemblyCache_iface;
49 LONG refs;
50 HANDLE lock;
51 };
52
53 static inline struct cache *impl_from_IAssemblyCache(IAssemblyCache *iface)
54 {
55 return CONTAINING_RECORD(iface, struct cache, IAssemblyCache_iface);
56 }
57
58 static HRESULT WINAPI cache_QueryInterface(
59 IAssemblyCache *iface,
60 REFIID riid,
61 void **obj )
62 {
63 struct cache *cache = impl_from_IAssemblyCache(iface);
64
65 TRACE("%p, %s, %p\n", cache, debugstr_guid(riid), obj);
66
67 *obj = NULL;
68
69 if (IsEqualIID(riid, &IID_IUnknown) ||
70 IsEqualIID(riid, &IID_IAssemblyCache))
71 {
72 IUnknown_AddRef( iface );
73 *obj = cache;
74 return S_OK;
75 }
76
77 return E_NOINTERFACE;
78 }
79
80 static ULONG WINAPI cache_AddRef( IAssemblyCache *iface )
81 {
82 struct cache *cache = impl_from_IAssemblyCache(iface);
83 return InterlockedIncrement( &cache->refs );
84 }
85
86 static ULONG WINAPI cache_Release( IAssemblyCache *iface )
87 {
88 struct cache *cache = impl_from_IAssemblyCache(iface);
89 ULONG refs = InterlockedDecrement( &cache->refs );
90
91 if (!refs)
92 {
93 TRACE("destroying %p\n", cache);
94 CloseHandle( cache->lock );
95 HeapFree( GetProcessHeap(), 0, cache );
96 }
97 return refs;
98 }
99
100 static unsigned int build_sxs_path( WCHAR *path )
101 {
102 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\',0};
103 unsigned int len = GetWindowsDirectoryW( path, MAX_PATH );
104
105 memcpy( path + len, winsxsW, sizeof(winsxsW) );
106 return len + sizeof(winsxsW) / sizeof(winsxsW[0]) - 1;
107 }
108
109 static WCHAR *build_assembly_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
110 const WCHAR *version, unsigned int *len )
111 {
112 static const WCHAR fmtW[] =
113 {'%','s','_','%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
114 unsigned int buflen = sizeof(fmtW) / sizeof(fmtW[0]);
115 WCHAR *ret, *p;
116
117 buflen += strlenW( arch );
118 buflen += strlenW( name );
119 buflen += strlenW( token );
120 buflen += strlenW( version );
121 if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL;
122 *len = sprintfW( ret, fmtW, arch, name, token, version );
123 for (p = ret; *p; p++) *p = tolowerW( *p );
124 return ret;
125 }
126
127 static WCHAR *build_manifest_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
128 const WCHAR *version )
129 {
130 static const WCHAR fmtW[] =
131 {'%','s','m','a','n','i','f','e','s','t','s','\\','%','s','.','m','a','n','i','f','e','s','t',0};
132 WCHAR *path = NULL, *ret, sxsdir[MAX_PATH];
133 unsigned int len;
134
135 if (!(path = build_assembly_name( arch, name, token, version, &len ))) return NULL;
136 len += sizeof(fmtW) / sizeof(fmtW[0]);
137 len += build_sxs_path( sxsdir );
138 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
139 {
140 HeapFree( GetProcessHeap(), 0, path );
141 return NULL;
142 }
143 sprintfW( ret, fmtW, sxsdir, path );
144 HeapFree( GetProcessHeap(), 0, path );
145 return ret;
146 }
147
148 static WCHAR *build_policy_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
149 unsigned int *len )
150 {
151 static const WCHAR fmtW[] =
152 {'%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0};
153 unsigned int buflen = sizeof(fmtW) / sizeof(fmtW[0]);
154 WCHAR *ret, *p;
155
156 buflen += strlenW( arch );
157 buflen += strlenW( name );
158 buflen += strlenW( token );
159 if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL;
160 *len = sprintfW( ret, fmtW, arch, name, token );
161 for (p = ret; *p; p++) *p = tolowerW( *p );
162 return ret;
163 }
164
165 static WCHAR *build_policy_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
166 const WCHAR *version )
167 {
168 static const WCHAR fmtW[] =
169 {'%','s','p','o','l','i','c','i','e','s','\\','%','s','\\','%','s','.','p','o','l','i','c','y',0};
170 WCHAR *path = NULL, *ret, sxsdir[MAX_PATH];
171 unsigned int len;
172
173 if (!(path = build_policy_name( arch, name, token, &len ))) return NULL;
174 len += sizeof(fmtW) / sizeof(fmtW[0]);
175 len += build_sxs_path( sxsdir );
176 len += strlenW( version );
177 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
178 {
179 HeapFree( GetProcessHeap(), 0, path );
180 return NULL;
181 }
182 sprintfW( ret, fmtW, sxsdir, path, version );
183 HeapFree( GetProcessHeap(), 0, path );
184 return ret;
185 }
186
187 static void cache_lock( struct cache *cache )
188 {
189 WaitForSingleObject( cache->lock, INFINITE );
190 }
191
192 static void cache_unlock( struct cache *cache )
193 {
194 ReleaseMutex( cache->lock );
195 }
196
197 #define ASSEMBLYINFO_FLAG_INSTALLED 1
198
199 static HRESULT WINAPI cache_QueryAssemblyInfo(
200 IAssemblyCache *iface,
201 DWORD flags,
202 LPCWSTR assembly_name,
203 ASSEMBLY_INFO *info )
204 {
205 struct cache *cache = impl_from_IAssemblyCache( iface );
206 IAssemblyName *name_obj;
207 const WCHAR *arch, *name, *token, *type, *version;
208 WCHAR *p, *path = NULL;
209 unsigned int len;
210 HRESULT hr;
211
212 TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(assembly_name), info);
213
214 if (flags || (info && info->cbAssemblyInfo != sizeof(*info)))
215 return E_INVALIDARG;
216
217 hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, 0 );
218 if (FAILED( hr ))
219 return hr;
220
221 arch = get_name_attribute( name_obj, NAME_ATTR_ID_ARCH );
222 name = get_name_attribute( name_obj, NAME_ATTR_ID_NAME );
223 token = get_name_attribute( name_obj, NAME_ATTR_ID_TOKEN );
224 type = get_name_attribute( name_obj, NAME_ATTR_ID_TYPE );
225 version = get_name_attribute( name_obj, NAME_ATTR_ID_VERSION );
226 if (!arch || !name || !token || !type || !version)
227 {
228 IAssemblyName_Release( name_obj );
229 return HRESULT_FROM_WIN32( ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE );
230 }
231 if (!info)
232 {
233 IAssemblyName_Release( name_obj );
234 return S_OK;
235 }
236 cache_lock( cache );
237
238 if (!strcmpW( type, win32W )) path = build_manifest_path( arch, name, token, version );
239 else if (!strcmpW( type, win32_policyW )) path = build_policy_path( arch, name, token, version );
240 else
241 {
242 hr = HRESULT_FROM_WIN32( ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE );
243 goto done;
244 }
245 if (!path)
246 {
247 hr = E_OUTOFMEMORY;
248 goto done;
249 }
250 hr = S_OK;
251 if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES) /* FIXME: better check */
252 {
253 info->dwAssemblyFlags = ASSEMBLYINFO_FLAG_INSTALLED;
254 TRACE("assembly is installed\n");
255 }
256 if ((p = strrchrW( path, '\\' ))) *p = 0;
257 len = strlenW( path ) + 1;
258 if (info->pszCurrentAssemblyPathBuf)
259 {
260 if (info->cchBuf < len)
261 {
262 info->cchBuf = len;
263 hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
264 }
265 else strcpyW( info->pszCurrentAssemblyPathBuf, path );
266 }
267
268 done:
269 HeapFree( GetProcessHeap(), 0, path );
270 IAssemblyName_Release( name_obj );
271 cache_unlock( cache );
272 return hr;
273 }
274
275 static HRESULT WINAPI cache_CreateAssemblyCacheItem(
276 IAssemblyCache *iface,
277 DWORD flags,
278 PVOID reserved,
279 IAssemblyCacheItem **item,
280 LPCWSTR name )
281 {
282 FIXME("%p, 0x%08x, %p, %p, %s\n", iface, flags, reserved, item, debugstr_w(name));
283 return E_NOTIMPL;
284 }
285
286 static HRESULT WINAPI cache_Reserved(
287 IAssemblyCache *iface,
288 IUnknown **reserved)
289 {
290 FIXME("%p\n", reserved);
291 return E_NOTIMPL;
292 }
293
294 static BSTR get_attribute_value( IXMLDOMNamedNodeMap *map, const WCHAR *value_name )
295 {
296 HRESULT hr;
297 IXMLDOMNode *attr;
298 VARIANT var;
299 BSTR str;
300
301 str = SysAllocString( value_name );
302 hr = IXMLDOMNamedNodeMap_getNamedItem( map, str, &attr );
303 SysFreeString( str );
304 if (hr != S_OK) return NULL;
305
306 hr = IXMLDOMNode_get_nodeValue( attr, &var );
307 IXMLDOMNode_Release( attr );
308 if (hr != S_OK) return NULL;
309 if (V_VT(&var) != VT_BSTR)
310 {
311 VariantClear( &var );
312 return NULL;
313 }
314 TRACE("%s=%s\n", debugstr_w(value_name), debugstr_w(V_BSTR( &var )));
315 return V_BSTR( &var );
316 }
317
318 struct file
319 {
320 struct list entry;
321 BSTR name;
322 };
323
324 struct assembly
325 {
326 BSTR type;
327 BSTR name;
328 BSTR version;
329 BSTR arch;
330 BSTR token;
331 struct list files;
332 };
333
334 static void free_assembly( struct assembly *assembly )
335 {
336 struct list *item, *cursor;
337
338 if (!assembly) return;
339 SysFreeString( assembly->type );
340 SysFreeString( assembly->name );
341 SysFreeString( assembly->version );
342 SysFreeString( assembly->arch );
343 SysFreeString( assembly->token );
344 LIST_FOR_EACH_SAFE( item, cursor, &assembly->files )
345 {
346 struct file *file = LIST_ENTRY( item, struct file, entry );
347 list_remove( &file->entry );
348 SysFreeString( file->name );
349 HeapFree( GetProcessHeap(), 0, file );
350 }
351 HeapFree( GetProcessHeap(), 0, assembly );
352 }
353
354 static HRESULT parse_files( IXMLDOMDocument *doc, struct assembly *assembly )
355 {
356 static const WCHAR fileW[] = {'f','i','l','e',0};
357 static const WCHAR nameW[] = {'n','a','m','e',0};
358 IXMLDOMNamedNodeMap *attrs;
359 IXMLDOMNodeList *list;
360 IXMLDOMNode *node;
361 struct file *f;
362 BSTR str;
363 HRESULT hr;
364 LONG len;
365
366 str = SysAllocString( fileW );
367 hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
368 SysFreeString( str );
369 if (hr != S_OK) return hr;
370
371 hr = IXMLDOMNodeList_get_length( list, &len );
372 if (hr != S_OK) goto done;
373 TRACE("found %d files\n", len);
374 if (!len)
375 {
376 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
377 goto done;
378 }
379
380 for (;;)
381 {
382 hr = IXMLDOMNodeList_nextNode( list, &node );
383 if (hr != S_OK || !node)
384 {
385 hr = S_OK;
386 break;
387 }
388
389 /* FIXME: validate node type */
390
391 hr = IXMLDOMNode_get_attributes( node, &attrs );
392 IXMLDOMNode_Release( node );
393 if (hr != S_OK)
394 goto done;
395
396 if (!(f = HeapAlloc( GetProcessHeap(), 0, sizeof(struct file) )))
397 {
398 IXMLDOMNamedNodeMap_Release( attrs );
399 hr = E_OUTOFMEMORY;
400 goto done;
401 }
402
403 f->name = get_attribute_value( attrs, nameW );
404 IXMLDOMNamedNodeMap_Release( attrs );
405 if (!f->name)
406 {
407 HeapFree( GetProcessHeap(), 0, f );
408 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
409 goto done;
410 }
411 list_add_tail( &assembly->files, &f->entry );
412 }
413
414 if (list_empty( &assembly->files ))
415 {
416 WARN("no files found\n");
417 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
418 }
419
420 done:
421 IXMLDOMNodeList_Release( list );
422 return hr;
423 }
424
425 static HRESULT parse_assembly( IXMLDOMDocument *doc, struct assembly **assembly )
426 {
427 static const WCHAR identityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
428 static const WCHAR typeW[] = {'t','y','p','e',0};
429 static const WCHAR nameW[] = {'n','a','m','e',0};
430 static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
431 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};
432 static const WCHAR tokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
433 IXMLDOMNodeList *list = NULL;
434 IXMLDOMNode *node = NULL;
435 IXMLDOMNamedNodeMap *attrs = NULL;
436 struct assembly *a = NULL;
437 BSTR str;
438 HRESULT hr;
439 LONG len;
440
441 str = SysAllocString( identityW );
442 hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
443 SysFreeString( str );
444 if (hr != S_OK) goto done;
445
446 hr = IXMLDOMNodeList_get_length( list, &len );
447 if (hr != S_OK) goto done;
448 if (!len)
449 {
450 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
451 goto done;
452 }
453 hr = IXMLDOMNodeList_nextNode( list, &node );
454 if (hr != S_OK) goto done;
455 if (!node)
456 {
457 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
458 goto done;
459 }
460 if (!(a = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct assembly) )))
461 {
462 hr = E_OUTOFMEMORY;
463 goto done;
464 }
465 list_init( &a->files );
466
467 hr = IXMLDOMNode_get_attributes( node, &attrs );
468 if (hr != S_OK) goto done;
469
470 a->type = get_attribute_value( attrs, typeW );
471 a->name = get_attribute_value( attrs, nameW );
472 a->version = get_attribute_value( attrs, versionW );
473 a->arch = get_attribute_value( attrs, architectureW );
474 a->token = get_attribute_value( attrs, tokenW );
475
476 if (!a->type || (strcmpW( a->type, win32W ) && strcmpW( a->type, win32_policyW )) ||
477 !a->name || !a->version || !a->arch || !a->token)
478 {
479 WARN("invalid win32 assembly\n");
480 hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
481 goto done;
482 }
483 if (!strcmpW( a->type, win32W )) hr = parse_files( doc, a );
484
485 done:
486 if (attrs) IXMLDOMNamedNodeMap_Release( attrs );
487 if (node) IXMLDOMNode_Release( node );
488 if (list) IXMLDOMNodeList_Release( list );
489 if (hr == S_OK) *assembly = a;
490 else free_assembly( a );
491 return hr;
492 }
493
494 static WCHAR *build_policy_filename( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
495 const WCHAR *version )
496 {
497 static const WCHAR policiesW[] = {'p','o','l','i','c','i','e','s','\\',0};
498 static const WCHAR suffixW[] = {'.','p','o','l','i','c','y',0};
499 WCHAR sxsdir[MAX_PATH], *ret, *fullname;
500 unsigned int len;
501
502 if (!(fullname = build_policy_name( arch, name, token, &len ))) return NULL;
503 len += build_sxs_path( sxsdir );
504 len += sizeof(policiesW) / sizeof(policiesW[0]) - 1;
505 len += strlenW( version );
506 len += sizeof(suffixW) / sizeof(suffixW[0]) - 1;
507 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
508 {
509 HeapFree( GetProcessHeap(), 0, fullname );
510 return NULL;
511 }
512 strcpyW( ret, sxsdir );
513 strcatW( ret, policiesW );
514 CreateDirectoryW( ret, NULL );
515 strcatW( ret, name );
516 CreateDirectoryW( ret, NULL );
517 strcatW( ret, backslashW );
518 strcatW( ret, version );
519 strcatW( ret, suffixW );
520
521 HeapFree( GetProcessHeap(), 0, fullname );
522 return ret;
523 }
524
525 static HRESULT install_policy( const WCHAR *manifest, struct assembly *assembly )
526 {
527 WCHAR *dst;
528 BOOL ret;
529
530 /* FIXME: handle catalog file */
531
532 dst = build_policy_filename( assembly->arch, assembly->name, assembly->token, assembly->version );
533 if (!dst) return E_OUTOFMEMORY;
534
535 ret = CopyFileW( manifest, dst, FALSE );
536 HeapFree( GetProcessHeap(), 0, dst );
537 if (!ret)
538 {
539 HRESULT hr = HRESULT_FROM_WIN32( GetLastError() );
540 WARN("failed to copy policy manifest file 0x%08x\n", hr);
541 return hr;
542 }
543 return S_OK;
544 }
545
546 static WCHAR *build_source_filename( const WCHAR *manifest, struct file *file )
547 {
548 WCHAR *src;
549 const WCHAR *p;
550 int len;
551
552 p = strrchrW( manifest, '\\' );
553 if (!p) p = strrchrW( manifest, '/' );
554 if (!p) return strdupW( manifest );
555
556 len = p - manifest + 1;
557 if (!(src = HeapAlloc( GetProcessHeap(), 0, (len + strlenW( file->name ) + 1) * sizeof(WCHAR) )))
558 return NULL;
559
560 memcpy( src, manifest, len * sizeof(WCHAR) );
561 strcpyW( src + len, file->name );
562 return src;
563 }
564
565 static WCHAR *build_manifest_filename( const WCHAR *arch, const WCHAR *name, const WCHAR *token,
566 const WCHAR *version )
567 {
568 static const WCHAR manifestsW[] = {'m','a','n','i','f','e','s','t','s','\\',0};
569 static const WCHAR suffixW[] = {'.','m','a','n','i','f','e','s','t',0};
570 WCHAR sxsdir[MAX_PATH], *ret, *fullname;
571 unsigned int len;
572
573 if (!(fullname = build_assembly_name( arch, name, token, version, &len ))) return NULL;
574 len += build_sxs_path( sxsdir );
575 len += sizeof(manifestsW) / sizeof(manifestsW[0]) - 1;
576 len += sizeof(suffixW) / sizeof(suffixW[0]) - 1;
577 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
578 {
579 HeapFree( GetProcessHeap(), 0, fullname );
580 return NULL;
581 }
582 strcpyW( ret, sxsdir );
583 strcatW( ret, manifestsW );
584 strcatW( ret, fullname );
585 strcatW( ret, suffixW );
586
587 HeapFree( GetProcessHeap(), 0, fullname );
588 return ret;
589 }
590
591 static HRESULT load_manifest( IXMLDOMDocument *doc, const WCHAR *filename )
592 {
593 HRESULT hr;
594 VARIANT var;
595 VARIANT_BOOL b;
596 BSTR str;
597
598 str = SysAllocString( filename );
599 VariantInit( &var );
600 V_VT( &var ) = VT_BSTR;
601 V_BSTR( &var ) = str;
602 hr = IXMLDOMDocument_load( doc, var, &b );
603 SysFreeString( str );
604 if (hr != S_OK) return hr;
605 if (!b)
606 {
607 WARN("failed to load manifest\n");
608 return S_FALSE;
609 }
610 return S_OK;
611 }
612
613 static HRESULT install_assembly( const WCHAR *manifest, struct assembly *assembly )
614 {
615 WCHAR sxsdir[MAX_PATH], *p, *name, *dst, *src;
616 unsigned int len, len_name, len_sxsdir = build_sxs_path( sxsdir );
617 struct file *file;
618 HRESULT hr = E_OUTOFMEMORY;
619 BOOL ret;
620
621 dst = build_manifest_filename( assembly->arch, assembly->name, assembly->token, assembly->version );
622 if (!dst) return E_OUTOFMEMORY;
623
624 ret = CopyFileW( manifest, dst, FALSE );
625 HeapFree( GetProcessHeap(), 0, dst );
626 if (!ret)
627 {
628 hr = HRESULT_FROM_WIN32( GetLastError() );
629 WARN("failed to copy manifest file 0x%08x\n", hr);
630 return hr;
631 }
632
633 name = build_assembly_name( assembly->arch, assembly->name, assembly->token, assembly->version,
634 &len_name );
635 if (!name) return E_OUTOFMEMORY;
636
637 /* FIXME: this should be a transaction */
638 LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
639 {
640 if (!(src = build_source_filename( manifest, file ))) goto done;
641
642 len = len_sxsdir + len_name + strlenW( file->name );
643 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) )))
644 {
645 HeapFree( GetProcessHeap(), 0, src );
646 goto done;
647 }
648 strcpyW( dst, sxsdir );
649 strcatW( dst, name );
650 CreateDirectoryW( dst, NULL );
651
652 strcatW( dst, backslashW );
653 strcatW( dst, file->name );
654 for (p = dst; *p; p++) *p = tolowerW( *p );
655
656 ret = CopyFileW( src, dst, FALSE );
657 HeapFree( GetProcessHeap(), 0, src );
658 HeapFree( GetProcessHeap(), 0, dst );
659 if (!ret)
660 {
661 hr = HRESULT_FROM_WIN32( GetLastError() );
662 WARN("failed to copy file 0x%08x\n", hr);
663 goto done;
664 }
665 }
666 hr = S_OK;
667
668 done:
669 HeapFree( GetProcessHeap(), 0, name );
670 return hr;
671 }
672
673 static HRESULT WINAPI cache_InstallAssembly(
674 IAssemblyCache *iface,
675 DWORD flags,
676 LPCWSTR path,
677 LPCFUSION_INSTALL_REFERENCE ref )
678 {
679 struct cache *cache = impl_from_IAssemblyCache( iface );
680 HRESULT hr, init;
681 IXMLDOMDocument *doc = NULL;
682 struct assembly *assembly = NULL;
683
684 TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(path), ref);
685
686 cache_lock( cache );
687 init = CoInitialize( NULL );
688
689 hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
690 if (hr != S_OK)
691 goto done;
692
693 if ((hr = load_manifest( doc, path )) != S_OK) goto done;
694 if ((hr = parse_assembly( doc, &assembly )) != S_OK) goto done;
695
696 /* FIXME: verify name attributes */
697
698 if (!strcmpW( assembly->type, win32_policyW ))
699 hr = install_policy( path, assembly );
700 else
701 hr = install_assembly( path, assembly );
702
703 done:
704 free_assembly( assembly );
705 if (doc) IXMLDOMDocument_Release( doc );
706 if (SUCCEEDED(init)) CoUninitialize();
707 cache_unlock( cache );
708 return hr;
709 }
710
711 static HRESULT uninstall_assembly( struct assembly *assembly )
712 {
713 WCHAR sxsdir[MAX_PATH], *name, *dirname, *filename;
714 unsigned int len, len_name, len_sxsdir = build_sxs_path( sxsdir );
715 HRESULT hr = E_OUTOFMEMORY;
716 struct file *file;
717
718 name = build_assembly_name( assembly->arch, assembly->name, assembly->token, assembly->version,
719 &len_name );
720 if (!name) return E_OUTOFMEMORY;
721 if (!(dirname = HeapAlloc( GetProcessHeap(), 0, (len_sxsdir + len_name + 1) * sizeof(WCHAR) )))
722 goto done;
723 strcpyW( dirname, sxsdir );
724 strcpyW( dirname + len_sxsdir, name );
725
726 LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
727 {
728 len = len_sxsdir + len_name + 1 + strlenW( file->name );
729 if (!(filename = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) goto done;
730 strcpyW( filename, dirname );
731 strcatW( filename, backslashW );
732 strcatW( filename, file->name );
733
734 if (!DeleteFileW( filename )) WARN( "failed to delete file %u\n", GetLastError() );
735 HeapFree( GetProcessHeap(), 0, filename );
736 }
737 RemoveDirectoryW( dirname );
738 hr = S_OK;
739
740 done:
741 HeapFree( GetProcessHeap(), 0, dirname );
742 HeapFree( GetProcessHeap(), 0, name );
743 return hr;
744 }
745
746 static HRESULT WINAPI cache_UninstallAssembly(
747 IAssemblyCache *iface,
748 DWORD flags,
749 LPCWSTR assembly_name,
750 LPCFUSION_INSTALL_REFERENCE ref,
751 ULONG *disp )
752 {
753 struct cache *cache = impl_from_IAssemblyCache( iface );
754 HRESULT hr, init;
755 IXMLDOMDocument *doc = NULL;
756 struct assembly *assembly = NULL;
757 IAssemblyName *name_obj = NULL;
758 const WCHAR *arch, *name, *token, *type, *version;
759 WCHAR *p, *path = NULL;
760
761 TRACE("%p, 0x%08x, %s, %p, %p\n", iface, flags, debugstr_w(assembly_name), ref, disp);
762
763 if (ref)
764 {
765 FIXME("application reference not supported\n");
766 return E_NOTIMPL;
767 }
768 cache_lock( cache );
769 init = CoInitialize( NULL );
770
771 hr = CreateAssemblyNameObject( &name_obj, assembly_name, CANOF_PARSE_DISPLAY_NAME, NULL );
772 if (FAILED( hr ))
773 goto done;
774
775 arch = get_name_attribute( name_obj, NAME_ATTR_ID_ARCH );
776 name = get_name_attribute( name_obj, NAME_ATTR_ID_NAME );
777 token = get_name_attribute( name_obj, NAME_ATTR_ID_TOKEN );
778 type = get_name_attribute( name_obj, NAME_ATTR_ID_TYPE );
779 version = get_name_attribute( name_obj, NAME_ATTR_ID_VERSION );
780 if (!arch || !name || !token || !type || !version)
781 {
782 hr = E_INVALIDARG;
783 goto done;
784 }
785 if (!strcmpW( type, win32W )) path = build_manifest_filename( arch, name, token, version );
786 else if (!strcmpW( type, win32_policyW )) path = build_policy_filename( arch, name, token, version );
787 else
788 {
789 hr = E_INVALIDARG;
790 goto done;
791 }
792
793 hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
794 if (hr != S_OK)
795 goto done;
796
797 if ((hr = load_manifest( doc, path )) != S_OK) goto done;
798 if ((hr = parse_assembly( doc, &assembly )) != S_OK) goto done;
799
800 if (!DeleteFileW( path )) WARN( "unable to remove manifest file %u\n", GetLastError() );
801 else if ((p = strrchrW( path, '\\' )))
802 {
803 *p = 0;
804 RemoveDirectoryW( path );
805 }
806 if (!strcmpW( assembly->type, win32W )) hr = uninstall_assembly( assembly );
807
808 done:
809 if (name_obj) IAssemblyName_Release( name_obj );
810 HeapFree( GetProcessHeap(), 0, path );
811 free_assembly( assembly );
812 if (doc) IXMLDOMDocument_Release( doc );
813 if (SUCCEEDED(init)) CoUninitialize();
814 cache_unlock( cache );
815 return hr;
816 }
817
818 static const IAssemblyCacheVtbl cache_vtbl =
819 {
820 cache_QueryInterface,
821 cache_AddRef,
822 cache_Release,
823 cache_UninstallAssembly,
824 cache_QueryAssemblyInfo,
825 cache_CreateAssemblyCacheItem,
826 cache_Reserved,
827 cache_InstallAssembly
828 };
829
830 /******************************************************************
831 * CreateAssemblyCache (SXS.@)
832 */
833 HRESULT WINAPI CreateAssemblyCache( IAssemblyCache **obj, DWORD reserved )
834 {
835 struct cache *cache;
836
837 TRACE("%p, %u\n", obj, reserved);
838
839 if (!obj)
840 return E_INVALIDARG;
841
842 *obj = NULL;
843
844 cache = HeapAlloc( GetProcessHeap(), 0, sizeof(struct cache) );
845 if (!cache)
846 return E_OUTOFMEMORY;
847
848 cache->IAssemblyCache_iface.lpVtbl = &cache_vtbl;
849 cache->refs = 1;
850 cache->lock = CreateMutexW( NULL, FALSE, cache_mutex_nameW );
851 if (!cache->lock)
852 {
853 HeapFree( GetProcessHeap(), 0, cache );
854 return HRESULT_FROM_WIN32( GetLastError() );
855 }
856 *obj = &cache->IAssemblyCache_iface;
857 return S_OK;
858 }