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 #ifdef __REACTOS__ 23 #include <wchar.h> 24 #endif 25 26 #define COBJMACROS 27 #define INITGUID 28 29 #include "windef.h" 30 #include "winbase.h" 31 #include "ole2.h" 32 #include "winsxs.h" 33 #include "msxml2.h" 34 35 #include "wine/debug.h" 36 #include "wine/list.h" 37 #include "sxs_private.h" 38 39 WINE_DEFAULT_DEBUG_CHANNEL(sxs); 40 41 static const WCHAR cache_mutex_nameW[] = 42 {'_','_','W','I','N','E','_','S','X','S','_','C','A','C','H','E','_','M','U','T','E','X','_','_',0}; 43 44 static const WCHAR win32W[] = {'w','i','n','3','2',0}; 45 static const WCHAR win32_policyW[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0}; 46 static const WCHAR backslashW[] = {'\\',0}; 47 48 struct cache 49 { 50 IAssemblyCache IAssemblyCache_iface; 51 LONG refs; 52 HANDLE lock; 53 }; 54 55 static inline struct cache *impl_from_IAssemblyCache(IAssemblyCache *iface) 56 { 57 return CONTAINING_RECORD(iface, struct cache, IAssemblyCache_iface); 58 } 59 60 static HRESULT WINAPI cache_QueryInterface( 61 IAssemblyCache *iface, 62 REFIID riid, 63 void **obj ) 64 { 65 struct cache *cache = impl_from_IAssemblyCache(iface); 66 67 TRACE("%p, %s, %p\n", cache, debugstr_guid(riid), obj); 68 69 *obj = NULL; 70 71 if (IsEqualIID(riid, &IID_IUnknown) || 72 IsEqualIID(riid, &IID_IAssemblyCache)) 73 { 74 IAssemblyCache_AddRef( iface ); 75 *obj = cache; 76 return S_OK; 77 } 78 79 return E_NOINTERFACE; 80 } 81 82 static ULONG WINAPI cache_AddRef( IAssemblyCache *iface ) 83 { 84 struct cache *cache = impl_from_IAssemblyCache(iface); 85 return InterlockedIncrement( &cache->refs ); 86 } 87 88 static ULONG WINAPI cache_Release( IAssemblyCache *iface ) 89 { 90 struct cache *cache = impl_from_IAssemblyCache(iface); 91 ULONG refs = InterlockedDecrement( &cache->refs ); 92 93 if (!refs) 94 { 95 TRACE("destroying %p\n", cache); 96 CloseHandle( cache->lock ); 97 HeapFree( GetProcessHeap(), 0, cache ); 98 } 99 return refs; 100 } 101 102 static unsigned int build_sxs_path( WCHAR *path ) 103 { 104 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\',0}; 105 unsigned int len = GetWindowsDirectoryW( path, MAX_PATH ); 106 107 memcpy( path + len, winsxsW, sizeof(winsxsW) ); 108 return len + ARRAY_SIZE(winsxsW) - 1; 109 } 110 111 static WCHAR *build_assembly_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token, 112 const WCHAR *version, unsigned int *len ) 113 { 114 static const WCHAR fmtW[] = 115 {'%','s','_','%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0}; 116 unsigned int buflen = ARRAY_SIZE(fmtW); 117 WCHAR *ret; 118 119 buflen += lstrlenW( arch ); 120 buflen += lstrlenW( name ); 121 buflen += lstrlenW( token ); 122 buflen += lstrlenW( version ); 123 if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL; 124 *len = swprintf( ret, fmtW, arch, name, token, version ); 125 return _wcslwr( ret ); 126 } 127 128 static WCHAR *build_manifest_path( const WCHAR *arch, const WCHAR *name, const WCHAR *token, 129 const WCHAR *version ) 130 { 131 static const WCHAR fmtW[] = 132 {'%','s','m','a','n','i','f','e','s','t','s','\\','%','s','.','m','a','n','i','f','e','s','t',0}; 133 WCHAR *path = NULL, *ret, sxsdir[MAX_PATH]; 134 unsigned int len; 135 136 if (!(path = build_assembly_name( arch, name, token, version, &len ))) return NULL; 137 len += ARRAY_SIZE(fmtW); 138 len += build_sxs_path( sxsdir ); 139 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 140 { 141 HeapFree( GetProcessHeap(), 0, path ); 142 return NULL; 143 } 144 swprintf( ret, fmtW, sxsdir, path ); 145 HeapFree( GetProcessHeap(), 0, path ); 146 return ret; 147 } 148 149 static WCHAR *build_policy_name( const WCHAR *arch, const WCHAR *name, const WCHAR *token, 150 unsigned int *len ) 151 { 152 static const WCHAR fmtW[] = 153 {'%','s','_','%','s','_','%','s','_','n','o','n','e','_','d','e','a','d','b','e','e','f',0}; 154 unsigned int buflen = ARRAY_SIZE(fmtW); 155 WCHAR *ret; 156 157 buflen += lstrlenW( arch ); 158 buflen += lstrlenW( name ); 159 buflen += lstrlenW( token ); 160 if (!(ret = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) ))) return NULL; 161 *len = swprintf( ret, fmtW, arch, name, token ); 162 return _wcslwr( 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 += ARRAY_SIZE(fmtW); 175 len += build_sxs_path( sxsdir ); 176 len += lstrlenW( version ); 177 if (!(ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) 178 { 179 HeapFree( GetProcessHeap(), 0, path ); 180 return NULL; 181 } 182 swprintf( 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 (!wcscmp( type, win32W )) path = build_manifest_path( arch, name, token, version ); 239 else if (!wcscmp( 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 = wcsrchr( path, '\\' ))) *p = 0; 257 len = lstrlenW( 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 lstrcpyW( 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 || (wcscmp( a->type, win32W ) && wcscmp( 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 (!wcscmp( 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 += ARRAY_SIZE(policiesW) - 1; 505 len += lstrlenW( version ); 506 len += ARRAY_SIZE(suffixW) - 1; 507 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) 508 { 509 HeapFree( GetProcessHeap(), 0, fullname ); 510 return NULL; 511 } 512 lstrcpyW( ret, sxsdir ); 513 lstrcatW( ret, policiesW ); 514 CreateDirectoryW( ret, NULL ); 515 lstrcatW( ret, name ); 516 CreateDirectoryW( ret, NULL ); 517 lstrcatW( ret, backslashW ); 518 lstrcatW( ret, version ); 519 lstrcatW( 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 = wcsrchr( manifest, '\\' ); 553 if (!p) p = wcsrchr( manifest, '/' ); 554 if (!p) return strdupW( manifest ); 555 556 len = p - manifest + 1; 557 if (!(src = HeapAlloc( GetProcessHeap(), 0, (len + lstrlenW( file->name ) + 1) * sizeof(WCHAR) ))) 558 return NULL; 559 560 memcpy( src, manifest, len * sizeof(WCHAR) ); 561 lstrcpyW( 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 += ARRAY_SIZE(manifestsW) - 1; 576 len += ARRAY_SIZE(suffixW) - 1; 577 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) 578 { 579 HeapFree( GetProcessHeap(), 0, fullname ); 580 return NULL; 581 } 582 lstrcpyW( ret, sxsdir ); 583 lstrcatW( ret, manifestsW ); 584 lstrcatW( ret, fullname ); 585 lstrcatW( 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 + lstrlenW( file->name ); 643 if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) 644 { 645 HeapFree( GetProcessHeap(), 0, src ); 646 goto done; 647 } 648 lstrcpyW( dst, sxsdir ); 649 lstrcatW( dst, name ); 650 CreateDirectoryW( dst, NULL ); 651 652 lstrcatW( dst, backslashW ); 653 lstrcatW( dst, file->name ); 654 for (p = dst; *p; p++) *p = towlower( *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 (!wcscmp( 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 lstrcpyW( dirname, sxsdir ); 724 lstrcpyW( dirname + len_sxsdir, name ); 725 726 LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry ) 727 { 728 len = len_sxsdir + len_name + 1 + lstrlenW( file->name ); 729 if (!(filename = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) goto done; 730 lstrcpyW( filename, dirname ); 731 lstrcatW( filename, backslashW ); 732 lstrcatW( 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 (!wcscmp( type, win32W )) path = build_manifest_filename( arch, name, token, version ); 786 else if (!wcscmp( 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 = wcsrchr( path, '\\' ))) 802 { 803 *p = 0; 804 RemoveDirectoryW( path ); 805 } 806 if (!wcscmp( 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 } 859