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;
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))
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 ) )
}
}
+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 ) )
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 );
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)
{
}
}
+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;
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 )
{
TRACE("Database is a patch\n");
szPersist -= MSIDBOPEN_PATCHFILE;
+ patch = TRUE;
}
save_path = szDBPath;
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 )
{
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 )