Commit 0dba391d authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

msi: Don't write streams to storage until the database is committed.

Native allows streams to be created with names that exceed the maximum length allowed by OLE storages. These streams can be used normally, it's just not possible to commit such a database.
parent db334624
......@@ -54,35 +54,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
#define IS_INTMSIDBOPEN(x) (((ULONG_PTR)(x) >> 16) == 0)
typedef struct tagMSITRANSFORM {
struct list entry;
IStorage *stg;
} MSITRANSFORM;
UINT msi_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
{
HRESULT r;
WCHAR decoded[MAX_STREAM_NAME_LEN + 1];
decode_streamname( stname, decoded );
TRACE("%s -> %s\n", debugstr_w(stname), debugstr_w(decoded));
r = IStorage_OpenStream( db->storage, stname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
if (FAILED( r ))
{
MSITRANSFORM *transform;
LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
{
r = IStorage_OpenStream( transform->stg, stname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
if (SUCCEEDED( r ))
break;
}
}
return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
}
static void free_transforms( MSIDATABASE *db )
{
while( !list_empty( &db->transforms ) )
......@@ -94,6 +65,16 @@ static void free_transforms( MSIDATABASE *db )
}
}
static void free_streams( MSIDATABASE *db )
{
UINT i;
for (i = 0; i < db->num_streams; i++)
{
if (db->streams[i].stream) IStream_Release( db->streams[i].stream );
}
msi_free( db->streams );
}
void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
{
MSITRANSFORM *t;
......@@ -109,6 +90,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
MSIDATABASE *db = (MSIDATABASE *) arg;
msi_free(db->path);
free_streams( db );
free_cached_tables( db );
free_transforms( db );
if (db->strings) msi_destroy_stringtable( db->strings );
......
......@@ -80,6 +80,18 @@ struct tagMSIOBJECTHDR
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000
#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID 30000
typedef struct tagMSISTREAM
{
UINT str_index;
IStream *stream;
} MSISTREAM;
typedef struct tagMSITRANSFORM
{
struct list entry;
IStorage *stg;
} MSITRANSFORM;
typedef struct tagMSIDATABASE
{
MSIOBJECTHDR hdr;
......@@ -93,6 +105,9 @@ typedef struct tagMSIDATABASE
UINT media_transform_disk_id;
struct list tables;
struct list transforms;
MSISTREAM *streams;
UINT num_streams;
UINT num_streams_allocated;
} MSIDATABASE;
typedef struct tagMSIVIEW MSIVIEW;
......@@ -741,6 +756,7 @@ extern void msi_free_handle_table(void) DECLSPEC_HIDDEN;
extern void free_cached_tables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
extern UINT MSI_CommitTables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
extern UINT msi_commit_streams( MSIDATABASE *db ) DECLSPEC_HIDDEN;
/* string table functions */
......@@ -828,8 +844,7 @@ extern LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) DECLSPEC_HIDDEN;
extern BOOL decode_streamname(LPCWSTR in, LPWSTR out) DECLSPEC_HIDDEN;
/* database internals */
extern UINT msi_get_raw_stream( MSIDATABASE *, LPCWSTR, IStream ** ) DECLSPEC_HIDDEN;
void msi_destroy_stream( MSIDATABASE *, const WCHAR * ) DECLSPEC_HIDDEN;
extern UINT msi_get_stream( MSIDATABASE *, const WCHAR *, IStream ** ) DECLSPEC_HIDDEN;
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ) DECLSPEC_HIDDEN;
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ) DECLSPEC_HIDDEN;
extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ) DECLSPEC_HIDDEN;
......
......@@ -840,8 +840,13 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
/* FIXME: lock the database */
r = MSI_CommitTables( db );
if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
r = msi_commit_streams( db );
if (r != ERROR_SUCCESS) ERR("Failed to commit streams!\n");
else
{
r = MSI_CommitTables( db );
if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n");
}
/* FIXME: unlock the database */
......
......@@ -1149,25 +1149,23 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT r;
LPWSTR encname, full_name = NULL;
WCHAR *name;
if( !view->ops->fetch_int )
return ERROR_INVALID_PARAMETER;
r = msi_stream_name( tv, row, &full_name );
if ( r != ERROR_SUCCESS )
r = msi_stream_name( tv, row, &name );
if (r != ERROR_SUCCESS)
{
ERR("fetching stream, error = %d\n", r);
ERR("fetching stream, error = %u\n", r);
return r;
}
encname = encode_streamname( FALSE, full_name );
r = msi_get_raw_stream( tv->db, encname, stm );
if( r )
ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
r = msi_get_stream( tv->db, name, stm );
if (r != ERROR_SUCCESS)
ERR("fetching stream %s, error = %u\n", debugstr_w(name), r);
msi_free( full_name );
msi_free( encname );
msi_free( name );
return r;
}
......
......@@ -1669,6 +1669,28 @@ static void test_streamtable(void)
MsiViewClose( view );
MsiCloseHandle( view );
/* try again */
create_file( "test1.txt" );
rec = MsiCreateRecord( 2 );
MsiRecordSetStringA( rec, 1, "data1" );
r = MsiRecordSetStreamA( rec, 2, "test1.txt" );
ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
DeleteFileA( "test1.txt" );
r = MsiDatabaseOpenViewA( hdb,
"INSERT INTO `_Streams` ( `Name`, `Data` ) VALUES ( ?, ? )", &view );
ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r );
r = MsiViewExecute( view, rec );
ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
MsiCloseHandle( rec );
MsiViewClose( view );
MsiCloseHandle( view );
r = MsiDatabaseOpenViewA( hdb,
"SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
......@@ -1758,7 +1780,7 @@ static void test_streamtable(void)
memset(buf, 0, MAX_PATH);
r = MsiRecordReadStream( rec, 2, buf, &size );
ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r);
todo_wine ok( !lstrcmpA(buf, "test2.txt\n"), "Expected 'test2.txt\\n', got %s\n", buf);
ok( !lstrcmpA(buf, "test2.txt\n"), "Expected 'test2.txt\\n', got %s\n", buf);
MsiCloseHandle( rec );
MsiViewClose( view );
......@@ -1790,10 +1812,41 @@ static void test_binary(void)
ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
DeleteFileA( "test.txt" );
/* try a name that exceeds maximum OLE stream name length */
query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'encryption.dll.CB4E6205_F99A_4C51_ADD4_184506EFAB87', 10000, ? )";
r = run_query( hdb, rec, query );
ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
r = MsiCloseHandle( rec );
ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
r = MsiDatabaseCommit( hdb );
ok( r == ERROR_FUNCTION_FAILED , "got %u\n", r );
r = MsiCloseHandle( hdb );
ok( r == ERROR_SUCCESS , "Failed to close database\n" );
r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb );
ok( r == ERROR_SUCCESS , "Failed to open database\n" );
query = "CREATE TABLE `Binary` ( `Name` CHAR(72) NOT NULL, `ID` INT NOT NULL, `Data` OBJECT PRIMARY KEY `Name`, `ID`)";
r = run_query( hdb, 0, query );
ok( r == ERROR_SUCCESS, "Cannot create Binary table: %d\n", r );
create_file( "test.txt" );
rec = MsiCreateRecord( 1 );
r = MsiRecordSetStreamA( rec, 1, "test.txt" );
ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r );
DeleteFileA( "test.txt" );
query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
r = run_query( hdb, rec, query );
ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r );
query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
r = run_query( hdb, rec, query );
ok( r == ERROR_FUNCTION_FAILED, "got %u\n", r );
r = MsiCloseHandle( rec );
ok( r == ERROR_SUCCESS , "Failed to close record handle\n" );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment