- Merge from trunk
[reactos.git] / dll / win32 / msi / database.c
index 8ec2411..3007d48 100644 (file)
@@ -126,8 +126,10 @@ static UINT clone_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
 UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
 {
     HRESULT r;
+    WCHAR decoded[MAX_STREAM_NAME_LEN];
 
-    TRACE("%s\n", debugstr_w(stname));
+    decode_streamname( stname, decoded );
+    TRACE("%s -> %s\n", debugstr_w(stname), debugstr_w(decoded));
 
     if (clone_open_stream( db, stname, stm ) == ERROR_SUCCESS)
         return ERROR_SUCCESS;
@@ -140,7 +142,6 @@ UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
 
         LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
         {
-            TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
             r = IStorage_OpenStream( transform->stg, stname, NULL,
                                      STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
             if (SUCCEEDED(r))
@@ -164,64 +165,6 @@ UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
     return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
 }
 
-UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
-                              USHORT **pdata, UINT *psz )
-{
-    HRESULT r;
-    UINT ret = ERROR_FUNCTION_FAILED;
-    VOID *data;
-    ULONG sz, count;
-    IStream *stm = NULL;
-    STATSTG stat;
-    LPWSTR encname;
-
-    encname = encode_streamname( FALSE, stname );
-    r = db_get_raw_stream( db, encname, &stm );
-    msi_free( encname );
-
-    if( r != ERROR_SUCCESS)
-        return ret;
-
-    r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
-    if( FAILED( r ) )
-    {
-        WARN("open stream failed r = %08x!\n", r);
-        goto end;
-    }
-
-    if( stat.cbSize.QuadPart >> 32 )
-    {
-        WARN("Too big!\n");
-        goto end;
-    }
-
-    sz = stat.cbSize.QuadPart;
-    data = msi_alloc( sz );
-    if( !data )
-    {
-        WARN("couldn't allocate memory r=%08x!\n", r);
-        ret = ERROR_NOT_ENOUGH_MEMORY;
-        goto end;
-    }
-
-    r = IStream_Read(stm, data, sz, &count );
-    if( FAILED( r ) || ( count != sz ) )
-    {
-        msi_free( data );
-        WARN("read stream failed r = %08x!\n", r);
-        goto end;
-    }
-
-    *pdata = data;
-    *psz = sz;
-    ret = ERROR_SUCCESS;
-
-end:
-    IStream_Release( stm );
-
-    return ret;
-}
-
 static void free_transforms( MSIDATABASE *db )
 {
     while( !list_empty( &db->transforms ) )
@@ -234,6 +177,37 @@ static void free_transforms( MSIDATABASE *db )
     }
 }
 
+void db_destroy_stream( MSIDATABASE *db, LPCWSTR stname )
+{
+    MSISTREAM *stream, *stream2;
+
+    LIST_FOR_EACH_ENTRY_SAFE( stream, stream2, &db->streams, MSISTREAM, entry )
+    {
+        HRESULT r;
+        STATSTG stat;
+
+        r = IStream_Stat( stream->stm, &stat, 0 );
+        if (FAILED(r))
+        {
+            WARN("failed to stat stream r = %08x\n", r);
+            continue;
+        }
+
+        if (!strcmpW( stname, stat.pwcsName ))
+        {
+            TRACE("destroying %s\n", debugstr_w(stname));
+
+            list_remove( &stream->entry );
+            IStream_Release( stream->stm );
+            msi_free( stream );
+            IStorage_DestroyElement( db->storage, stname );
+            CoTaskMemFree( stat.pwcsName );
+            break;
+        }
+        CoTaskMemFree( stat.pwcsName );
+    }
+}
+
 static void free_streams( MSIDATABASE *db )
 {
     while( !list_empty( &db->streams ) )
@@ -253,7 +227,7 @@ void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
     t = msi_alloc( sizeof *t );
     t->stg = stg;
     IStorage_AddRef( stg );
-    list_add_tail( &db->transforms, &t->entry );
+    list_add_head( &db->transforms, &t->entry );
 
     /* the transform may add or replace streams */
     free_streams( db );
@@ -267,7 +241,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
     free_cached_tables( db );
     free_streams( db );
     free_transforms( db );
-    msi_destroy_stringtable( db->strings );
+    if (db->strings) msi_destroy_stringtable( db->strings );
     IStorage_Release( db->storage );
     if (db->deletefile)
     {
@@ -281,6 +255,43 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
     }
 }
 
+static HRESULT db_initialize( IStorage *stg, const GUID *clsid )
+{
+    static const WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
+    HRESULT hr;
+
+    hr = IStorage_SetClass( stg, clsid );
+    if (FAILED( hr ))
+    {
+        WARN("failed to set class id 0x%08x\n", hr);
+        return hr;
+    }
+
+    /* create the _Tables stream */
+    hr = write_stream_data( stg, szTables, NULL, 0, TRUE );
+    if (FAILED( hr ))
+    {
+        WARN("failed to create _Tables stream 0x%08x\n", hr);
+        return hr;
+    }
+
+    hr = msi_init_string_table( stg );
+    if (FAILED( hr ))
+    {
+        WARN("failed to initialize string table 0x%08x\n", hr);
+        return hr;
+    }
+
+    hr = IStorage_Commit( stg, 0 );
+    if (FAILED( hr ))
+    {
+        WARN("failed to commit changes 0x%08x\n", hr);
+        return hr;
+    }
+
+    return S_OK;
+}
+
 UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
 {
     IStorage *stg = NULL;
@@ -289,11 +300,9 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
     UINT ret = ERROR_FUNCTION_FAILED;
     LPCWSTR szMode, save_path;
     STATSTG stat;
-    BOOL created = FALSE;
+    BOOL created = FALSE, patch = FALSE;
     WCHAR path[MAX_PATH];
 
-    static const WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
-
     TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
 
     if( !pdb )
@@ -304,6 +313,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
     {
         TRACE("Database is a patch\n");
         szPersist -= MSIDBOPEN_PATCHFILE;
+        patch = TRUE;
     }
 
     save_path = szDBPath;
@@ -323,28 +333,28 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
         r = StgOpenStorage( szDBPath, NULL,
               STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
     }
-    else if( szPersist == MSIDBOPEN_CREATE || szPersist == MSIDBOPEN_CREATEDIRECT )
+    else if( szPersist == MSIDBOPEN_CREATE )
     {
-        /* FIXME: MSIDBOPEN_CREATE should case STGM_TRANSACTED flag to be
-         * used here: */
         r = StgCreateDocfile( szDBPath,
-              STGM_CREATE|STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
-        if( r == ERROR_SUCCESS )
-        {
-            IStorage_SetClass( stg, &CLSID_MsiDatabase );
-            /* create the _Tables stream */
-            r = write_stream_data(stg, szTables, NULL, 0, TRUE);
-            if (SUCCEEDED(r))
-                r = msi_init_string_table( stg );
-        }
+              STGM_CREATE|STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg );
+
+        if( SUCCEEDED(r) )
+            r = db_initialize( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase );
+        created = TRUE;
+    }
+    else if( szPersist == MSIDBOPEN_CREATEDIRECT )
+    {
+        r = StgCreateDocfile( szDBPath,
+              STGM_CREATE|STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg );
+
+        if( SUCCEEDED(r) )
+            r = db_initialize( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase );
         created = TRUE;
     }
     else if( szPersist == MSIDBOPEN_TRANSACT )
     {
-        /* FIXME: MSIDBOPEN_TRANSACT should case STGM_TRANSACTED flag to be
-         * used here: */
         r = StgOpenStorage( szDBPath, NULL,
-              STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
+              STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
     }
     else if( szPersist == MSIDBOPEN_DIRECT )
     {
@@ -379,6 +389,14 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
         goto end;
     }
 
+    if ( patch && !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) )
+    {
+        ERR("storage GUID is not the MSI patch GUID %s\n",
+             debugstr_guid(&stat.clsid) );
+        ret = ERROR_OPEN_FAILED;
+        goto end;
+    }
+
     db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
                               MSI_CloseDatabase );
     if( !db )
@@ -2057,7 +2075,7 @@ static ULONG WINAPI mrd_Release( IWineMsiRemoteDatabase *iface )
 }
 
 static HRESULT WINAPI mrd_IsTablePersistent( IWineMsiRemoteDatabase *iface,
-                                             BSTR table, MSICONDITION *persistent )
+                                             LPCWSTR table, MSICONDITION *persistent )
 {
     msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
     *persistent = MsiDatabaseIsTablePersistentW(This->database, table);
@@ -2065,7 +2083,7 @@ static HRESULT WINAPI mrd_IsTablePersistent( IWineMsiRemoteDatabase *iface,
 }
 
 static HRESULT WINAPI mrd_GetPrimaryKeys( IWineMsiRemoteDatabase *iface,
-                                          BSTR table, MSIHANDLE *keys )
+                                          LPCWSTR table, MSIHANDLE *keys )
 {
     msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
     UINT r = MsiDatabaseGetPrimaryKeysW(This->database, table, keys);
@@ -2081,7 +2099,7 @@ static HRESULT WINAPI mrd_GetSummaryInformation( IWineMsiRemoteDatabase *iface,
 }
 
 static HRESULT WINAPI mrd_OpenView( IWineMsiRemoteDatabase *iface,
-                                    BSTR query, MSIHANDLE *view )
+                                    LPCWSTR query, MSIHANDLE *view )
 {
     msi_remote_database_impl *This = mrd_from_IWineMsiRemoteDatabase( iface );
     UINT r = MsiDatabaseOpenViewW(This->database, query, view);