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