diff options
author | Marc-André Lureau <marcandre.lureau@gmail.com> | 2012-12-18 17:27:05 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2013-01-09 13:56:07 +0100 |
commit | ef6554cff2a3b50df2ded82507be0d79efda1a0c (patch) | |
tree | a16762d60fd43da8aa38ff302d93a3dc8a9fe9f6 /libmsi | |
parent | 0a97c9f43718d34aacc834c60f3ced60e9ce956f (diff) | |
download | msitools-ef6554cff2a3b50df2ded82507be0d79efda1a0c.tar.gz msitools-ef6554cff2a3b50df2ded82507be0d79efda1a0c.tar.xz msitools-ef6554cff2a3b50df2ded82507be0d79efda1a0c.zip |
database: extract streams during table export
See also MSDN documentation about the import/export of tables with streams:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa370079%28v=vs.85%29.aspx
Diffstat (limited to 'libmsi')
-rw-r--r-- | libmsi/libmsi-database.c | 105 | ||||
-rw-r--r-- | libmsi/table.c | 5 |
2 files changed, 92 insertions, 18 deletions
diff --git a/libmsi/libmsi-database.c b/libmsi/libmsi-database.c index c66d4de..3c50a06 100644 --- a/libmsi/libmsi-database.c +++ b/libmsi/libmsi-database.c @@ -1219,37 +1219,101 @@ libmsi_database_import (LibmsiDatabase *db, return r == LIBMSI_RESULT_SUCCESS; } -static unsigned msi_export_record( int fd, LibmsiRecord *row, unsigned start ) +static gboolean +msi_export_stream (GsfInput *gsfin, GFile *table_dir, gchar **str, + GError **error) +{ + GError *err = NULL; + GFile *file = NULL; + GInputStream *in = NULL; + GOutputStream *out = NULL; + gssize spliced = -1; + + if (!table_dir) + goto end; + + if (!g_file_make_directory_with_parents (table_dir, NULL, &err) && + !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_EXISTS)) { + g_propagate_error (error, err); + goto end; + } + + *str = g_strdup (g_object_get_data (G_OBJECT (gsfin), "stname")); + file = g_file_get_child (table_dir, *str); + out = g_file_replace (file, NULL, FALSE, 0, NULL, error); + in = libmsi_istream_new (gsfin); + spliced = g_output_stream_splice (out, in, 0, NULL, NULL); + +end: + g_clear_error (&err); + if (file) + g_object_unref (file); + if (out) + g_object_unref (out); + if (in) + g_object_unref (in); + + return spliced != -1; + +} +static unsigned msi_export_record(int fd, LibmsiRecord *row, + unsigned start, GFile *table_dir, + GError **error) { + GsfInput *in = NULL; unsigned i, count; + unsigned success = LIBMSI_RESULT_FUNCTION_FAILED; count = libmsi_record_get_field_count (row); for (i = start; i <= count; i++) { char *str; - str = libmsi_record_get_string (row, i); - if (!str) - return LIBMSI_RESULT_FUNCTION_FAILED; + _libmsi_record_get_gsf_input (row, i, &in); + if (in) { + if (!msi_export_stream (in, table_dir, &str, error)) + goto end; + g_object_unref (in); + in = NULL; + } else { + str = libmsi_record_get_string (row, i); + if (!str) + goto end; + } /* TODO full_write */ if (write (fd, str, strlen (str)) != strlen (str)) { g_free (str); - return LIBMSI_RESULT_FUNCTION_FAILED; + goto end; } g_free (str); const char *sep = (i < count) ? "\t" : "\r\n"; if (write (fd, sep, strlen (sep)) != strlen (sep)) - return LIBMSI_RESULT_FUNCTION_FAILED; + goto end; } - return LIBMSI_RESULT_SUCCESS; + success = LIBMSI_RESULT_SUCCESS; + +end: + if (in) + g_object_unref (in); + + return success; } +typedef struct _ExportRow { + int fd; + GFile *table_dir; + GError **error; +} ExportRow; + static unsigned msi_export_row( LibmsiRecord *row, void *arg ) { - return msi_export_record( (intptr_t) arg, row, 1 ); + ExportRow *export = arg; + + return msi_export_record (export->fd, row, 1, + export->table_dir, export->error); } static unsigned msi_export_forcecodepage( int fd, unsigned codepage ) @@ -1267,8 +1331,8 @@ static unsigned msi_export_forcecodepage( int fd, unsigned codepage ) return LIBMSI_RESULT_SUCCESS; } -static unsigned _libmsi_database_export( LibmsiDatabase *db, const char *table, - int fd) +static unsigned _libmsi_database_export(LibmsiDatabase *db, const char *table, + int fd, GError **error) { static const char query[] = "select * from %s"; static const char forcecodepage[] = "_ForceCodepage"; @@ -1292,7 +1356,7 @@ static unsigned _libmsi_database_export( LibmsiDatabase *db, const char *table, r = _libmsi_query_get_column_info(view, LIBMSI_COL_INFO_NAMES, &rec); if (r == LIBMSI_RESULT_SUCCESS) { - msi_export_record( fd, rec, 1 ); + msi_export_record( fd, rec, 1, NULL, error); g_object_unref(rec); } @@ -1300,7 +1364,7 @@ static unsigned _libmsi_database_export( LibmsiDatabase *db, const char *table, r = _libmsi_query_get_column_info(view, LIBMSI_COL_INFO_TYPES, &rec); if (r == LIBMSI_RESULT_SUCCESS) { - msi_export_record( fd, rec, 1 ); + msi_export_record( fd, rec, 1, NULL, error); g_object_unref(rec); } @@ -1309,13 +1373,20 @@ static unsigned _libmsi_database_export( LibmsiDatabase *db, const char *table, if (r == LIBMSI_RESULT_SUCCESS) { libmsi_record_set_string( rec, 0, table ); - msi_export_record( fd, rec, 0 ); + msi_export_record( fd, rec, 0, NULL, error); g_object_unref(rec); } /* write out row 4 onwards, the data */ - r = _libmsi_query_iterate_records( view, 0, msi_export_row, (void *)(intptr_t) fd ); - g_object_unref(view); + ExportRow export = { + .fd = fd, + .table_dir = g_file_new_for_path (table), + .error = error + }; + r = _libmsi_query_iterate_records( view, 0, msi_export_row, &export); + + g_object_unref (export.table_dir); + g_object_unref (view); } done: @@ -1358,10 +1429,10 @@ libmsi_database_export (LibmsiDatabase *db, g_return_val_if_fail (!error || *error == NULL, FALSE); g_object_ref(db); - r = _libmsi_database_export(db, table, fd); + r = _libmsi_database_export (db, table, fd, error); g_object_unref(db); - if (r != LIBMSI_RESULT_SUCCESS) + if (r != LIBMSI_RESULT_SUCCESS && error && !*error) g_set_error (error, LIBMSI_RESULT_ERROR, r, G_STRFUNC); return r == LIBMSI_RESULT_SUCCESS; diff --git a/libmsi/table.c b/libmsi/table.c index 4a7439b..16057e3 100644 --- a/libmsi/table.c +++ b/libmsi/table.c @@ -1163,7 +1163,10 @@ static unsigned table_view_fetch_stream( LibmsiView *view, unsigned row, unsigne if( r ) ERR("fetching stream %s, error = %d\n",debugstr_a(full_name), r); - msi_free( full_name ); + if (*stm) + g_object_set_data_full (G_OBJECT (*stm), "stname", full_name, g_free); + else + msi_free( full_name ); msi_free( encname ); return r; } |