sxs: Add support for installing side-by-side assemblies.

Hans Leidekker hans at codeweavers.com
Fri Nov 5 05:36:49 CDT 2010


---
 dlls/sxs/Makefile.in |    1 +
 dlls/sxs/cache.c     |  377 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 376 insertions(+), 2 deletions(-)

diff --git a/dlls/sxs/Makefile.in b/dlls/sxs/Makefile.in
index f218293..180f91c 100644
--- a/dlls/sxs/Makefile.in
+++ b/dlls/sxs/Makefile.in
@@ -1,4 +1,5 @@
 MODULE    = sxs.dll
+IMPORTS   = oleaut32 ole32
 
 C_SRCS = \
 	cache.c \
diff --git a/dlls/sxs/cache.c b/dlls/sxs/cache.c
index b6cf47e..cd5f26c 100644
--- a/dlls/sxs/cache.c
+++ b/dlls/sxs/cache.c
@@ -27,10 +27,22 @@
 #include "winbase.h"
 #include "ole2.h"
 #include "winsxs.h"
+#include "msxml2.h"
+
 #include "wine/debug.h"
+#include "wine/list.h"
+#include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(sxs);
 
+static inline WCHAR *strdupW( const WCHAR *s )
+{
+    WCHAR *t;
+    if (!s) return NULL;
+    if ((t = HeapAlloc( GetProcessHeap(), 0, (strlenW( s ) + 1) * sizeof(WCHAR) ))) strcpyW( t, s );
+    return t;
+}
+
 struct cache
 {
     const IAssemblyCacheVtbl *vtbl;
@@ -118,14 +130,375 @@ static HRESULT WINAPI cache_Reserved(
     return E_NOTIMPL;
 }
 
+static BSTR get_attribute_value( IXMLDOMNamedNodeMap *map, const WCHAR *value_name )
+{
+    HRESULT hr;
+    IXMLDOMNode *attr;
+    VARIANT var;
+    BSTR str;
+
+    str = SysAllocString( value_name );
+    hr = IXMLDOMNamedNodeMap_getNamedItem( map, str, &attr );
+    SysFreeString( str );
+    if (hr != S_OK) return NULL;
+
+    hr = IXMLDOMNode_get_nodeValue( attr, &var );
+    IXMLDOMNode_Release( attr );
+    if (hr != S_OK) return NULL;
+    if (V_VT(&var) != VT_BSTR)
+    {
+        VariantClear( &var );
+        return NULL;
+    }
+    TRACE("%s=%s\n", debugstr_w(value_name), debugstr_w(V_BSTR( &var )));
+    return V_BSTR( &var );
+}
+
+struct file
+{
+    struct list entry;
+    BSTR name;
+};
+
+struct assembly
+{
+    BSTR type;
+    BSTR name;
+    BSTR version;
+    BSTR arch;
+    BSTR token;
+    struct list files;
+};
+
+static void free_assembly( struct assembly *assembly )
+{
+    struct list *item, *cursor;
+
+    if (!assembly) return;
+    SysFreeString( assembly->type );
+    SysFreeString( assembly->name );
+    SysFreeString( assembly->version );
+    SysFreeString( assembly->arch );
+    SysFreeString( assembly->token );
+    LIST_FOR_EACH_SAFE( item, cursor, &assembly->files )
+    {
+        struct file *file = LIST_ENTRY( item, struct file, entry );
+        list_remove( &file->entry );
+        SysFreeString( file->name );
+        HeapFree( GetProcessHeap(), 0, file );
+    }
+    HeapFree( GetProcessHeap(), 0, assembly );
+}
+
+static HRESULT parse_files( IXMLDOMDocument *doc, struct assembly *assembly )
+{
+    static const WCHAR fileW[] = {'f','i','l','e',0};
+    static const WCHAR nameW[] = {'n','a','m','e',0};
+    IXMLDOMNamedNodeMap *attrs;
+    IXMLDOMNodeList *list;
+    IXMLDOMNode *node;
+    struct file *f;
+    BSTR str;
+    HRESULT hr;
+    LONG len;
+
+    str = SysAllocString( fileW );
+    hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
+    SysFreeString( str );
+    if (hr != S_OK) return hr;
+
+    hr = IXMLDOMNodeList_get_length( list, &len );
+    if (hr != S_OK) goto done;
+    TRACE("found %d files\n", len);
+    if (!len)
+    {
+        hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
+        goto done;
+    }
+
+    for (;;)
+    {
+        hr = IXMLDOMNodeList_nextNode( list, &node );
+        if (hr != S_OK || !node)
+        {
+            hr = S_OK;
+            break;
+        }
+
+        /* FIXME: validate node type */
+
+        hr = IXMLDOMNode_get_attributes( node, &attrs );
+        IXMLDOMNode_Release( node );
+        if (hr != S_OK)
+            goto done;
+
+        if (!(f = HeapAlloc( GetProcessHeap(), 0, sizeof(struct file) )))
+        {
+            IXMLDOMNamedNodeMap_Release( attrs );
+            hr = E_OUTOFMEMORY;
+            goto done;
+        }
+
+        f->name = get_attribute_value( attrs, nameW );
+        IXMLDOMNamedNodeMap_Release( attrs );
+        if (!f->name)
+        {
+            HeapFree( GetProcessHeap(), 0, f );
+            hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
+            goto done;
+        }
+        list_add_tail( &assembly->files, &f->entry );
+    }
+
+    if (list_empty( &assembly->files ))
+    {
+        WARN("no files found\n");
+        hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
+    }
+
+done:
+    IXMLDOMNodeList_Release( list );
+    return hr;
+}
+
+static HRESULT parse_assembly( IXMLDOMDocument *doc, struct assembly **assembly )
+{
+    static const WCHAR identityW[] = {'a','s','s','e','m','b','l','y','I','d','e','n','t','i','t','y',0};
+    static const WCHAR typeW[] = {'t','y','p','e',0};
+    static const WCHAR nameW[] = {'n','a','m','e',0};
+    static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
+    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};
+    static const WCHAR tokenW[] = {'p','u','b','l','i','c','K','e','y','T','o','k','e','n',0};
+    static const WCHAR win32W[] = {'w','i','n','3','2',0};
+    static const WCHAR policyW[] = {'w','i','n','3','2','-','p','o','l','i','c','y',0};
+    IXMLDOMNodeList *list = NULL;
+    IXMLDOMNode *node = NULL;
+    IXMLDOMNamedNodeMap *attrs = NULL;
+    struct assembly *a = NULL;
+    BSTR str;
+    HRESULT hr;
+    LONG len;
+
+    str = SysAllocString( identityW );
+    hr = IXMLDOMDocument_getElementsByTagName( doc, str, &list );
+    SysFreeString( str );
+    if (hr != S_OK) goto done;
+
+    hr = IXMLDOMNodeList_get_length( list, &len );
+    if (hr != S_OK) goto done;
+    if (!len)
+    {
+        hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
+        goto done;
+    }
+    hr = IXMLDOMNodeList_nextNode( list, &node );
+    if (hr != S_OK) goto done;
+    if (!node)
+    {
+        hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
+        goto done;
+    }
+    if (!(a = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct assembly) )))
+    {
+        hr = E_OUTOFMEMORY;
+        goto done;
+    }
+    list_init( &a->files );
+
+    hr = IXMLDOMNode_get_attributes( node, &attrs );
+    if (hr != S_OK) goto done;
+
+    a->type = get_attribute_value( attrs, typeW );
+    if (a->type && !strcmpW( a->type, policyW ))
+    {
+        FIXME("ignoring policy assembly\n");
+        hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
+        goto done;
+    }
+    a->name    = get_attribute_value( attrs, nameW );
+    a->version = get_attribute_value( attrs, versionW );
+    a->arch    = get_attribute_value( attrs, architectureW );
+    a->token   = get_attribute_value( attrs, tokenW );
+
+    if (!a->type || strcmpW( a->type, win32W ) || !a->name || !a->version || !a->arch || !a->token)
+    {
+        WARN("invalid win32 assembly\n");
+        hr = ERROR_SXS_MANIFEST_FORMAT_ERROR;
+        goto done;
+    }
+
+    hr = parse_files( doc, a );
+
+done:
+    if (attrs) IXMLDOMNamedNodeMap_Release( attrs );
+    if (node) IXMLDOMNode_Release( node );
+    if (list) IXMLDOMNodeList_Release( list );
+    if (hr == S_OK) *assembly = a;
+    else free_assembly( a );
+    return hr;
+}
+
+static WCHAR *build_source_filename( const WCHAR *manifest, struct file *file )
+{
+    WCHAR *src;
+    const WCHAR *p;
+    int len;
+
+    p = strrchrW( manifest, '\\' );
+    if (!p) p = strrchrW( manifest, '/' );
+    if (!p) return strdupW( manifest );
+
+    len = p - manifest + 1;
+    if (!(src = HeapAlloc( GetProcessHeap(), 0, (len + strlenW( file->name ) + 1) * sizeof(WCHAR) )))
+        return NULL;
+
+    memcpy( src, manifest, len * sizeof(WCHAR) );
+    strcpyW( src + len, file->name );
+    return src;
+}
+
+static HRESULT install_assembly( const WCHAR *manifest, struct assembly *assembly )
+{
+    static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\',0};
+    static const WCHAR manifestsW[] = {'m','a','n','i','f','e','s','t','s','\\',0};
+    static const WCHAR deadbeefW[] = {'n','o','n','e','_','d','e','a','d','b','e','e','f',0};
+    static const WCHAR suffixW[] = {'.','m','a','n','i','f','e','s','t',0};
+    static const WCHAR backslashW[] = {'\\',0};
+    static const WCHAR fmtW[] = {'%','s','_','%','s','_','%','s','_','%','s','_','%','s',0};
+    WCHAR sxsdir[MAX_PATH], *p, *name, *dst, *src;
+    int len;
+    struct file *file;
+    HRESULT hr = S_OK;
+    BOOL ret;
+
+    GetWindowsDirectoryW( sxsdir, MAX_PATH );
+    strcatW( sxsdir, winsxsW );
+
+    len = strlenW( fmtW );
+    len += strlenW( assembly->arch );
+    len += strlenW( assembly->name );
+    len += strlenW( assembly->token );
+    len += strlenW( assembly->version );
+    len += strlenW( deadbeefW );
+
+    if (!(name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+        return E_OUTOFMEMORY;
+
+    len = sprintfW( name, fmtW, assembly->arch, assembly->name, assembly->token, assembly->version, deadbeefW );
+    for (p = name; *p; p++) *p = tolowerW( *p );
+
+    len += strlenW( sxsdir );
+    len += strlenW( manifestsW );
+    len += strlenW( suffixW );
+    if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
+    {
+        HeapFree( GetProcessHeap(), 0, name );
+        return E_OUTOFMEMORY;
+    }
+    strcpyW( dst, sxsdir );
+    strcatW( dst, manifestsW );
+    strcatW( dst, name );
+    strcatW( dst, suffixW );
+
+    ret = CopyFileW( manifest, dst, FALSE );
+    HeapFree( GetProcessHeap(), 0, dst );
+    if (!ret)
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        WARN("failed to copy manifest file 0x%08x\n", hr);
+        goto done;
+    }
+
+    /* FIXME: this should be a transaction */
+    LIST_FOR_EACH_ENTRY( file, &assembly->files, struct file, entry )
+    {
+        if (!(src = build_source_filename( manifest, file )))
+        {
+            hr = E_OUTOFMEMORY;
+            goto done;
+        }
+        len = strlenW( sxsdir ) + strlenW( name ) + strlenW( file->name );
+        if (!(dst = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) )))
+        {
+            HeapFree( GetProcessHeap(), 0, src );
+            hr = E_OUTOFMEMORY;
+            goto done;
+        }
+        strcpyW( dst, sxsdir );
+        strcatW( dst, name );
+        CreateDirectoryW( dst, NULL );
+
+        strcatW( dst, backslashW );
+        strcatW( dst, file->name );
+        for (p = dst; *p; p++) *p = tolowerW( *p );
+
+        ret = CopyFileW( src, dst, FALSE );
+        HeapFree( GetProcessHeap(), 0, src );
+        HeapFree( GetProcessHeap(), 0, dst );
+        if (!ret)
+        {
+            hr = HRESULT_FROM_WIN32( GetLastError() );
+            WARN("failed to copy file 0x%08x\n", hr);
+            goto done;
+        }
+    }
+
+done:
+    HeapFree( GetProcessHeap(), 0, name );
+    return hr;
+}
+
 static HRESULT WINAPI cache_InstallAssembly(
     IAssemblyCache *iface,
     DWORD flags,
     LPCWSTR path,
     LPCFUSION_INSTALL_REFERENCE ref )
 {
-    FIXME("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(path), ref);
-    return E_NOTIMPL;
+    HRESULT hr, init;
+    IXMLDOMDocument *doc = NULL;
+    struct assembly *assembly = NULL;
+    BSTR str;
+    VARIANT var;
+    VARIANT_BOOL b;
+
+    TRACE("%p, 0x%08x, %s, %p\n", iface, flags, debugstr_w(path), ref);
+
+    init = CoInitialize( NULL );
+
+    hr = CoCreateInstance( &CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc );
+    if (hr != S_OK)
+        goto done;
+
+    str = SysAllocString( path );
+    VariantInit( &var );
+    V_VT( &var ) = VT_BSTR;
+    V_BSTR( &var ) = str;
+    hr = IXMLDOMDocument_load( doc, var, &b );
+    SysFreeString( str );
+    if (hr != S_OK) goto done;
+    if (!b)
+    {
+        WARN("failed to load manifest\n");
+        hr = S_FALSE;
+        goto done;
+    }
+
+    hr = parse_assembly( doc, &assembly );
+    if (hr != S_OK)
+        goto done;
+
+    /* FIXME: verify name attributes */
+
+    hr = install_assembly( path, assembly );
+
+done:
+    free_assembly( assembly );
+    if (doc) IXMLDOMDocument_Release( doc );
+
+    if (SUCCEEDED(init))
+        CoUninitialize();
+
+    return hr;
 }
 
 static const IAssemblyCacheVtbl cache_vtbl =
-- 
1.7.1






More information about the wine-patches mailing list