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); ...@@ -54,35 +54,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
#define IS_INTMSIDBOPEN(x) (((ULONG_PTR)(x) >> 16) == 0) #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 ) static void free_transforms( MSIDATABASE *db )
{ {
while( !list_empty( &db->transforms ) ) while( !list_empty( &db->transforms ) )
...@@ -94,6 +65,16 @@ static void free_transforms( MSIDATABASE *db ) ...@@ -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 ) void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
{ {
MSITRANSFORM *t; MSITRANSFORM *t;
...@@ -109,6 +90,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) ...@@ -109,6 +90,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
MSIDATABASE *db = (MSIDATABASE *) arg; MSIDATABASE *db = (MSIDATABASE *) arg;
msi_free(db->path); msi_free(db->path);
free_streams( db );
free_cached_tables( db ); free_cached_tables( db );
free_transforms( db ); free_transforms( db );
if (db->strings) msi_destroy_stringtable( db->strings ); if (db->strings) msi_destroy_stringtable( db->strings );
......
...@@ -80,6 +80,18 @@ struct tagMSIOBJECTHDR ...@@ -80,6 +80,18 @@ struct tagMSIOBJECTHDR
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000 #define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET 10000
#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID 30000 #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 typedef struct tagMSIDATABASE
{ {
MSIOBJECTHDR hdr; MSIOBJECTHDR hdr;
...@@ -93,6 +105,9 @@ typedef struct tagMSIDATABASE ...@@ -93,6 +105,9 @@ typedef struct tagMSIDATABASE
UINT media_transform_disk_id; UINT media_transform_disk_id;
struct list tables; struct list tables;
struct list transforms; struct list transforms;
MSISTREAM *streams;
UINT num_streams;
UINT num_streams_allocated;
} MSIDATABASE; } MSIDATABASE;
typedef struct tagMSIVIEW MSIVIEW; typedef struct tagMSIVIEW MSIVIEW;
...@@ -741,6 +756,7 @@ extern void msi_free_handle_table(void) DECLSPEC_HIDDEN; ...@@ -741,6 +756,7 @@ extern void msi_free_handle_table(void) DECLSPEC_HIDDEN;
extern void free_cached_tables( MSIDATABASE *db ) DECLSPEC_HIDDEN; extern void free_cached_tables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
extern UINT MSI_CommitTables( MSIDATABASE *db ) DECLSPEC_HIDDEN; extern UINT MSI_CommitTables( MSIDATABASE *db ) DECLSPEC_HIDDEN;
extern UINT msi_commit_streams( MSIDATABASE *db ) DECLSPEC_HIDDEN;
/* string table functions */ /* string table functions */
...@@ -828,8 +844,7 @@ extern LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) DECLSPEC_HIDDEN; ...@@ -828,8 +844,7 @@ extern LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) DECLSPEC_HIDDEN;
extern BOOL decode_streamname(LPCWSTR in, LPWSTR out) DECLSPEC_HIDDEN; extern BOOL decode_streamname(LPCWSTR in, LPWSTR out) DECLSPEC_HIDDEN;
/* database internals */ /* database internals */
extern UINT msi_get_raw_stream( MSIDATABASE *, LPCWSTR, IStream ** ) DECLSPEC_HIDDEN; extern UINT msi_get_stream( MSIDATABASE *, const WCHAR *, IStream ** ) DECLSPEC_HIDDEN;
void msi_destroy_stream( MSIDATABASE *, const WCHAR * ) DECLSPEC_HIDDEN;
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ) DECLSPEC_HIDDEN; extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ) DECLSPEC_HIDDEN;
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ) DECLSPEC_HIDDEN; extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ) DECLSPEC_HIDDEN;
extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ) DECLSPEC_HIDDEN; extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ) DECLSPEC_HIDDEN;
......
...@@ -840,8 +840,13 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) ...@@ -840,8 +840,13 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
/* FIXME: lock the database */ /* FIXME: lock the database */
r = MSI_CommitTables( db ); r = msi_commit_streams( db );
if (r != ERROR_SUCCESS) ERR("Failed to commit tables!\n"); 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 */ /* FIXME: unlock the database */
......
...@@ -1149,25 +1149,23 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt ...@@ -1149,25 +1149,23 @@ static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, ISt
{ {
MSITABLEVIEW *tv = (MSITABLEVIEW*)view; MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT r; UINT r;
LPWSTR encname, full_name = NULL; WCHAR *name;
if( !view->ops->fetch_int ) if( !view->ops->fetch_int )
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
r = msi_stream_name( tv, row, &full_name ); r = msi_stream_name( tv, row, &name );
if ( r != ERROR_SUCCESS ) if (r != ERROR_SUCCESS)
{ {
ERR("fetching stream, error = %d\n", r); ERR("fetching stream, error = %u\n", r);
return r; return r;
} }
encname = encode_streamname( FALSE, full_name ); r = msi_get_stream( tv->db, name, stm );
r = msi_get_raw_stream( tv->db, encname, stm ); if (r != ERROR_SUCCESS)
if( r ) ERR("fetching stream %s, error = %u\n", debugstr_w(name), r);
ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r);
msi_free( full_name ); msi_free( name );
msi_free( encname );
return r; return r;
} }
......
...@@ -1669,6 +1669,28 @@ static void test_streamtable(void) ...@@ -1669,6 +1669,28 @@ static void test_streamtable(void)
MsiViewClose( view ); MsiViewClose( view );
MsiCloseHandle( 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, r = MsiDatabaseOpenViewA( hdb,
"SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view ); "SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = 'data'", &view );
ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r); ok( r == ERROR_SUCCESS, "Failed to open database view: %d\n", r);
...@@ -1758,7 +1780,7 @@ static void test_streamtable(void) ...@@ -1758,7 +1780,7 @@ static void test_streamtable(void)
memset(buf, 0, MAX_PATH); memset(buf, 0, MAX_PATH);
r = MsiRecordReadStream( rec, 2, buf, &size ); r = MsiRecordReadStream( rec, 2, buf, &size );
ok( r == ERROR_SUCCESS, "Failed to get stream: %d\n", r); 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 ); MsiCloseHandle( rec );
MsiViewClose( view ); MsiViewClose( view );
...@@ -1790,10 +1812,41 @@ static void test_binary(void) ...@@ -1790,10 +1812,41 @@ static void test_binary(void)
ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r); ok( r == ERROR_SUCCESS, "Failed to add stream data to the record: %d\n", r);
DeleteFileA( "test.txt" ); 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, ? )"; query = "INSERT INTO `Binary` ( `Name`, `ID`, `Data` ) VALUES ( 'filename1', 1, ? )";
r = run_query( hdb, rec, query ); r = run_query( hdb, rec, query );
ok( r == ERROR_SUCCESS, "Insert into Binary table failed: %d\n", r ); 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 ); r = MsiCloseHandle( rec );
ok( r == ERROR_SUCCESS , "Failed to close record handle\n" ); 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