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 } 848