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