mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Bug #105669: Add checks to detect errors on write, especially if there no space left on the disk.
Check the return value of fprintf and use ferror where libraries as libxml do the write. The change may not be perfect yet and a review would be nice. Still, it detects quite a few errors that, without it, slip through and may destroy valuable data. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18593 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
@@ -715,6 +715,9 @@ gnc_xml_be_write_to_file(FileBackend *fbe,
|
||||
tmp_name ? tmp_name : "(null)",
|
||||
strerror(errno) ? strerror(errno) : "");
|
||||
/* already in an error just flow on through */
|
||||
} else {
|
||||
/* Use a generic write error code */
|
||||
qof_backend_set_error(be, ERR_FILEIO_WRITE_ERROR);
|
||||
}
|
||||
g_free(tmp_name);
|
||||
LEAVE("");
|
||||
|
||||
@@ -150,22 +150,18 @@ gnc_book_dom_tree_create(QofBook *book)
|
||||
/* same as above, but we write out directly. Only handle the guid
|
||||
* and slots, everything else is handled elsewhere */
|
||||
|
||||
void
|
||||
gboolean
|
||||
write_book_parts(FILE *out, QofBook *book)
|
||||
{
|
||||
xmlNodePtr domnode;
|
||||
|
||||
domnode = guid_to_dom_tree(book_id_string, qof_book_get_guid(book));
|
||||
xmlElemDump(out, NULL, domnode);
|
||||
if (fprintf(out, "\n") < 0)
|
||||
{
|
||||
qof_backend_set_error(qof_book_get_backend(book),
|
||||
ERR_FILEIO_WRITE_ERROR);
|
||||
xmlFreeNode(domnode);
|
||||
return;
|
||||
}
|
||||
xmlFreeNode (domnode);
|
||||
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return FALSE;
|
||||
|
||||
if (qof_book_get_slots(book))
|
||||
{
|
||||
xmlNodePtr kvpnode = kvp_frame_to_dom_tree(book_slots_string,
|
||||
@@ -173,10 +169,14 @@ write_book_parts(FILE *out, QofBook *book)
|
||||
if (kvpnode)
|
||||
{
|
||||
xmlElemDump(out, NULL, kvpnode);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode(kvpnode);
|
||||
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -803,16 +803,17 @@ qof_session_load_from_xml_file_v2(FileBackend *fbe, QofBook *book)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
write_counts(FILE* out, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *type;
|
||||
gboolean success = TRUE;
|
||||
|
||||
va_start(ap, out);
|
||||
type = va_arg(ap, char *);
|
||||
|
||||
while (type)
|
||||
while (success && type)
|
||||
{
|
||||
int amount = va_arg(ap, int);
|
||||
|
||||
@@ -832,15 +833,23 @@ write_counts(FILE* out, ...)
|
||||
* 'type' at some point. */
|
||||
xmlSetProp(node, BAD_CAST "cd:type", BAD_CAST type);
|
||||
xmlNodeAddContent(node, BAD_CAST val);
|
||||
g_free(val);
|
||||
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
|
||||
g_free(val);
|
||||
xmlFreeNode(node);
|
||||
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
{
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
fprintf(out, "<%s %s=\"%s\">%d</%s>\n",
|
||||
COUNT_DATA_TAG, "cd:type", type, amount, COUNT_DATA_TAG);
|
||||
if (fprintf(out, "<%s %s=\"%s\">%d</%s>\n",
|
||||
COUNT_DATA_TAG, "cd:type", type, amount, COUNT_DATA_TAG) < 0)
|
||||
{
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -849,6 +858,7 @@ write_counts(FILE* out, ...)
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return success;
|
||||
}
|
||||
|
||||
static gint
|
||||
@@ -868,10 +878,10 @@ compare_commodity_ids(gconstpointer a, gconstpointer b)
|
||||
gnc_commodity_get_mnemonic(cb)));
|
||||
}
|
||||
|
||||
static void write_pricedb (FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
static void write_transactions (FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
static void write_template_transaction_data (FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
static void write_schedXactions(FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
static gboolean write_pricedb (FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
static gboolean write_transactions (FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
static gboolean write_template_transaction_data (FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
static gboolean write_schedXactions(FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
static void write_budget (QofInstance *ent, gpointer data);
|
||||
|
||||
static void
|
||||
@@ -898,11 +908,11 @@ write_data_cb (const char *type, gpointer data_p, gpointer be_data_p)
|
||||
g_return_if_fail (type && data && be_data);
|
||||
g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
|
||||
|
||||
if (data->write)
|
||||
if (data->write && !ferror(be_data->out))
|
||||
(data->write)(be_data->out, be_data->book);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
write_book(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
{
|
||||
struct file_backend be_data;
|
||||
@@ -919,72 +929,79 @@ write_book(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
|
||||
if (!node)
|
||||
{
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xmlElemDump(out, NULL, node);
|
||||
if (fprintf(out, "\n") < 0)
|
||||
xmlFreeNode(node);
|
||||
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
{
|
||||
qof_backend_set_error(qof_book_get_backend(book), ERR_FILEIO_WRITE_ERROR);
|
||||
return;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
xmlFreeNode(node);
|
||||
#endif
|
||||
|
||||
be_data.out = out;
|
||||
be_data.book = book;
|
||||
be_data.gd = gd;
|
||||
if (fprintf( out, "<%s version=\"%s\">\n", BOOK_TAG, gnc_v2_book_version_string) < 0)
|
||||
{
|
||||
qof_backend_set_error(qof_book_get_backend(book), ERR_FILEIO_WRITE_ERROR);
|
||||
return;
|
||||
}
|
||||
write_book_parts (out, book);
|
||||
return FALSE;
|
||||
if (!write_book_parts (out, book))
|
||||
return FALSE;
|
||||
|
||||
/* gd->counter.{foo}_total fields should have all these totals
|
||||
already collected. I don't know why we're re-calling all these
|
||||
functions. */
|
||||
write_counts(out,
|
||||
"commodity",
|
||||
gnc_commodity_table_get_size(
|
||||
gnc_book_get_commodity_table(book)),
|
||||
"account",
|
||||
1 + gnc_account_n_descendants(gnc_book_get_root_account(book)),
|
||||
"transaction",
|
||||
gnc_book_count_transactions(book),
|
||||
"schedxaction",
|
||||
g_list_length(gnc_book_get_schedxactions(book)->sx_list),
|
||||
"budget", qof_collection_count(
|
||||
qof_book_get_collection(book, GNC_ID_BUDGET)),
|
||||
NULL);
|
||||
if (!write_counts(out,
|
||||
"commodity",
|
||||
gnc_commodity_table_get_size(
|
||||
gnc_book_get_commodity_table(book)),
|
||||
"account",
|
||||
1 + gnc_account_n_descendants(gnc_book_get_root_account(book)),
|
||||
"transaction",
|
||||
gnc_book_count_transactions(book),
|
||||
"schedxaction",
|
||||
g_list_length(gnc_book_get_schedxactions(book)->sx_list),
|
||||
"budget", qof_collection_count(
|
||||
qof_book_get_collection(book, GNC_ID_BUDGET)),
|
||||
NULL))
|
||||
return FALSE;
|
||||
|
||||
qof_object_foreach_backend (GNC_FILE_BACKEND, write_counts_cb, &be_data);
|
||||
|
||||
write_commodities(out, book, gd);
|
||||
write_pricedb(out, book, gd);
|
||||
write_accounts(out, book, gd);
|
||||
write_transactions(out, book, gd);
|
||||
write_template_transaction_data(out, book, gd);
|
||||
write_schedXactions(out, book, gd);
|
||||
if (ferror(out)
|
||||
|| !write_commodities(out, book, gd)
|
||||
|| !write_pricedb(out, book, gd)
|
||||
|| !write_accounts(out, book, gd)
|
||||
|| !write_transactions(out, book, gd)
|
||||
|| !write_template_transaction_data(out, book, gd)
|
||||
|| !write_schedXactions(out, book, gd))
|
||||
|
||||
return FALSE;
|
||||
|
||||
qof_collection_foreach(qof_book_get_collection(book, GNC_ID_BUDGET),
|
||||
write_budget, &be_data);
|
||||
if (ferror(out))
|
||||
return FALSE;
|
||||
|
||||
qof_object_foreach_backend (GNC_FILE_BACKEND, write_data_cb, &be_data);
|
||||
if (ferror(out))
|
||||
return FALSE;
|
||||
|
||||
if (fprintf( out, "</%s>\n", BOOK_TAG ) < 0)
|
||||
{
|
||||
qof_backend_set_error(qof_book_get_backend(book), ERR_FILEIO_WRITE_ERROR);
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gboolean
|
||||
write_commodities(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
{
|
||||
gnc_commodity_table *tbl;
|
||||
GList *namespaces;
|
||||
GList *lp;
|
||||
gboolean success = TRUE;
|
||||
|
||||
tbl = gnc_book_get_commodity_table(book);
|
||||
|
||||
@@ -994,7 +1011,7 @@ write_commodities(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
namespaces = g_list_sort(namespaces, compare_namespaces);
|
||||
}
|
||||
|
||||
for (lp = namespaces; lp; lp = lp->next)
|
||||
for (lp = namespaces; success && lp; lp = lp->next)
|
||||
{
|
||||
GList *comms, *lp2;
|
||||
xmlNodePtr comnode;
|
||||
@@ -1009,7 +1026,11 @@ write_commodities(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
continue;
|
||||
|
||||
xmlElemDump(out, NULL, comnode);
|
||||
fprintf(out, "\n");
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
{
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
xmlFreeNode(comnode);
|
||||
gd->counter.commodities_loaded++;
|
||||
@@ -1020,9 +1041,11 @@ write_commodities(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
}
|
||||
|
||||
if (namespaces) g_list_free (namespaces);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
write_pricedb(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
{
|
||||
xmlNodePtr node;
|
||||
@@ -1031,13 +1054,16 @@ write_pricedb(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
|
||||
if (!node)
|
||||
{
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
|
||||
xmlFreeNode(node);
|
||||
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1049,27 +1075,30 @@ xml_add_trn_data(Transaction *t, gpointer data)
|
||||
node = gnc_transaction_dom_tree_create(t);
|
||||
|
||||
xmlElemDump(be_data->out, NULL, node);
|
||||
fprintf(be_data->out, "\n");
|
||||
|
||||
xmlFreeNode(node);
|
||||
|
||||
if (ferror(be_data->out) || fprintf(be_data->out, "\n") < 0)
|
||||
return -1;
|
||||
|
||||
be_data->gd->counter.transactions_loaded++;
|
||||
run_callback(be_data->gd, "transaction");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
write_transactions(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
{
|
||||
struct file_backend be_data;
|
||||
|
||||
be_data.out = out;
|
||||
be_data.gd = gd;
|
||||
xaccAccountTreeForEachTransaction(gnc_book_get_root_account(book),
|
||||
xml_add_trn_data,
|
||||
(gpointer) &be_data);
|
||||
return 0 ==
|
||||
xaccAccountTreeForEachTransaction(gnc_book_get_root_account(book),
|
||||
xml_add_trn_data,
|
||||
(gpointer) &be_data);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
write_template_transaction_data( FILE *out, QofBook *book, sixtp_gdv2 *gd )
|
||||
{
|
||||
Account *ra;
|
||||
@@ -1081,14 +1110,18 @@ write_template_transaction_data( FILE *out, QofBook *book, sixtp_gdv2 *gd )
|
||||
ra = gnc_book_get_template_root(book);
|
||||
if ( gnc_account_n_descendants(ra) > 0 )
|
||||
{
|
||||
fprintf( out, "<%s>\n", TEMPLATE_TRANSACTION_TAG );
|
||||
write_account_tree( out, ra, gd );
|
||||
xaccAccountTreeForEachTransaction( ra, xml_add_trn_data, (gpointer)&be_data );
|
||||
fprintf( out, "</%s>\n", TEMPLATE_TRANSACTION_TAG );
|
||||
if (fprintf(out, "<%s>\n", TEMPLATE_TRANSACTION_TAG) < 0
|
||||
|| !write_account_tree(out, ra, gd)
|
||||
|| xaccAccountTreeForEachTransaction(ra, xml_add_trn_data, (gpointer)&be_data)
|
||||
|| fprintf(out, "</%s>\n", TEMPLATE_TRANSACTION_TAG) < 0)
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
write_schedXactions( FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
{
|
||||
GList *schedXactions;
|
||||
@@ -1097,20 +1130,23 @@ write_schedXactions( FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
|
||||
schedXactions = gnc_book_get_schedxactions(book)->sx_list;
|
||||
|
||||
if ( schedXactions == NULL )
|
||||
return;
|
||||
if (schedXactions == NULL)
|
||||
return TRUE;
|
||||
|
||||
do
|
||||
{
|
||||
tmpSX = schedXactions->data;
|
||||
node = gnc_schedXaction_dom_tree_create( tmpSX );
|
||||
xmlElemDump( out, NULL, node );
|
||||
fprintf( out, "\n" );
|
||||
xmlFreeNode( node );
|
||||
xmlFreeNode(node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return FALSE;
|
||||
gd->counter.schedXactions_loaded++;
|
||||
run_callback(gd, "schedXactions");
|
||||
}
|
||||
while ( (schedXactions = schedXactions->next) );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1120,21 +1156,26 @@ write_budget (QofInstance *ent, gpointer data)
|
||||
struct file_backend* be = data;
|
||||
|
||||
GncBudget *bgt = GNC_BUDGET(ent);
|
||||
|
||||
if (ferror(be->out))
|
||||
return;
|
||||
|
||||
node = gnc_budget_dom_tree_create(bgt);
|
||||
xmlElemDump( be->out, NULL, node );
|
||||
fprintf( be->out, "\n" );
|
||||
xmlFreeNode( node );
|
||||
xmlFreeNode(node);
|
||||
if (ferror(be->out) || fprintf(be->out, "\n") < 0)
|
||||
return;
|
||||
|
||||
be->gd->counter.budgets_loaded++;
|
||||
run_callback(be->gd, "budgets");
|
||||
}
|
||||
|
||||
void
|
||||
gboolean
|
||||
gnc_xml2_write_namespace_decl (FILE *out, const char *namespace)
|
||||
{
|
||||
g_return_if_fail (namespace);
|
||||
fprintf(out, "\n xmlns:%s=\"http://www.gnucash.org/XML/%s\"",
|
||||
namespace, namespace);
|
||||
g_return_val_if_fail(namespace, FALSE);
|
||||
return fprintf(out, "\n xmlns:%s=\"http://www.gnucash.org/XML/%s\"",
|
||||
namespace, namespace) >= 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1146,36 +1187,41 @@ do_write_namespace_cb (const char *type, gpointer data_p, gpointer file_p)
|
||||
g_return_if_fail (type && data && out);
|
||||
g_return_if_fail (data->version == GNC_FILE_BACKEND_VERS);
|
||||
|
||||
if (data->ns)
|
||||
if (data->ns && !ferror(out))
|
||||
(data->ns)(out);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
write_v2_header (FILE *out)
|
||||
{
|
||||
fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
|
||||
fprintf(out, "<" GNC_V2_STRING);
|
||||
if (fprintf(out, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n") < 0
|
||||
|| fprintf(out, "<" GNC_V2_STRING) < 0
|
||||
|
||||
gnc_xml2_write_namespace_decl (out, "gnc");
|
||||
gnc_xml2_write_namespace_decl (out, "act");
|
||||
gnc_xml2_write_namespace_decl (out, "book");
|
||||
gnc_xml2_write_namespace_decl (out, "cd");
|
||||
gnc_xml2_write_namespace_decl (out, "cmdty");
|
||||
gnc_xml2_write_namespace_decl (out, "price");
|
||||
gnc_xml2_write_namespace_decl (out, "slot");
|
||||
gnc_xml2_write_namespace_decl (out, "split");
|
||||
gnc_xml2_write_namespace_decl (out, "sx");
|
||||
gnc_xml2_write_namespace_decl (out, "trn");
|
||||
gnc_xml2_write_namespace_decl (out, "ts");
|
||||
gnc_xml2_write_namespace_decl (out, "fs");
|
||||
gnc_xml2_write_namespace_decl (out, "bgt");
|
||||
gnc_xml2_write_namespace_decl (out, "recurrence");
|
||||
gnc_xml2_write_namespace_decl (out, "lot");
|
||||
|| !gnc_xml2_write_namespace_decl (out, "gnc")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "act")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "book")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "cd")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "cmdty")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "price")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "slot")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "split")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "sx")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "trn")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "ts")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "fs")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "bgt")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "recurrence")
|
||||
|| !gnc_xml2_write_namespace_decl (out, "lot"))
|
||||
|
||||
return FALSE;
|
||||
|
||||
/* now cope with the plugins */
|
||||
qof_object_foreach_backend (GNC_FILE_BACKEND, do_write_namespace_cb, out);
|
||||
|
||||
fprintf(out, ">\n");
|
||||
if (ferror(out) || fprintf(out, ">\n") < 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -1183,14 +1229,13 @@ gnc_book_write_to_xml_filehandle_v2(QofBook *book, FILE *out)
|
||||
{
|
||||
QofBackend *be;
|
||||
sixtp_gdv2 *gd;
|
||||
gboolean success = TRUE;
|
||||
|
||||
if (!out) return FALSE;
|
||||
|
||||
write_v2_header (out);
|
||||
|
||||
write_counts(out,
|
||||
"book", 1,
|
||||
NULL);
|
||||
if (!write_v2_header(out)
|
||||
|| !write_counts(out, "book", 1, NULL))
|
||||
return FALSE;
|
||||
|
||||
be = qof_book_get_backend(book);
|
||||
gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage);
|
||||
@@ -1204,12 +1249,12 @@ gnc_book_write_to_xml_filehandle_v2(QofBook *book, FILE *out)
|
||||
gd->counter.budgets_total = qof_collection_count(
|
||||
qof_book_get_collection(book, GNC_ID_BUDGET));
|
||||
|
||||
write_book(out, book, gd);
|
||||
|
||||
fprintf(out, "</" GNC_V2_STRING ">\n\n");
|
||||
if (!write_book(out, book, gd)
|
||||
|| fprintf(out, "</" GNC_V2_STRING ">\n\n") < 0)
|
||||
success = FALSE;
|
||||
|
||||
g_free(gd);
|
||||
return TRUE;
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1222,6 +1267,7 @@ gnc_book_write_accounts_to_xml_filehandle_v2(QofBackend *be, QofBook *book, FILE
|
||||
Account *root;
|
||||
int ncom, nacc;
|
||||
sixtp_gdv2 *gd;
|
||||
gboolean success = TRUE;
|
||||
|
||||
if (!out) return FALSE;
|
||||
|
||||
@@ -1231,25 +1277,21 @@ gnc_book_write_accounts_to_xml_filehandle_v2(QofBackend *be, QofBook *book, FILE
|
||||
table = gnc_book_get_commodity_table(book);
|
||||
ncom = gnc_commodity_table_get_size(table);
|
||||
|
||||
write_v2_header (out);
|
||||
|
||||
write_counts(out,
|
||||
"commodity", ncom,
|
||||
"account", nacc,
|
||||
NULL);
|
||||
if (!write_v2_header(out)
|
||||
|| !write_counts(out, "commodity", ncom, "account", nacc, NULL))
|
||||
return FALSE;
|
||||
|
||||
gd = gnc_sixtp_gdv2_new(book, TRUE, file_rw_feedback, be->percentage);
|
||||
gd->counter.commodities_total = ncom;
|
||||
gd->counter.accounts_total = nacc;
|
||||
|
||||
write_commodities(out, book, gd);
|
||||
|
||||
write_accounts(out, book, gd);
|
||||
|
||||
fprintf(out, "</" GNC_V2_STRING ">\n\n");
|
||||
if (!write_commodities(out, book, gd)
|
||||
|| !write_accounts(out, book, gd)
|
||||
|| fprintf(out, "</" GNC_V2_STRING ">\n\n") < 0)
|
||||
success = FALSE;
|
||||
|
||||
g_free(gd);
|
||||
return TRUE;
|
||||
return success;
|
||||
}
|
||||
|
||||
#define BUFLEN 4096
|
||||
@@ -1407,26 +1449,26 @@ gnc_book_write_to_xml_file_v2(
|
||||
gboolean compress)
|
||||
{
|
||||
FILE *out;
|
||||
gboolean success = TRUE;
|
||||
|
||||
out = try_gz_open(filename, "w", compress, TRUE);
|
||||
if (out == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gnc_book_write_to_xml_filehandle_v2 (book, out);
|
||||
/* Try to write as much as possible */
|
||||
if (!out
|
||||
|| !gnc_book_write_to_xml_filehandle_v2(book, out)
|
||||
|| !write_emacs_trailer(out))
|
||||
success = FALSE;
|
||||
|
||||
write_emacs_trailer(out);
|
||||
/* Close the output stream */
|
||||
if (out && fclose(out))
|
||||
success = FALSE;
|
||||
|
||||
if (fclose(out) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
/* Optionally wait for parallel compression threads */
|
||||
if (out && compress)
|
||||
if (!wait_for_gzip(out))
|
||||
success = FALSE;
|
||||
|
||||
if (compress)
|
||||
return wait_for_gzip(out);
|
||||
|
||||
return TRUE;
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1441,23 +1483,28 @@ gnc_book_write_accounts_to_xml_file_v2(
|
||||
const char *filename)
|
||||
{
|
||||
FILE *out;
|
||||
gboolean success = TRUE;
|
||||
|
||||
out = g_fopen(filename, "w");
|
||||
if (out == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
|
||||
/* Try to write as much as possible */
|
||||
if (!out
|
||||
|| !gnc_book_write_accounts_to_xml_filehandle_v2 (be, book, out)
|
||||
|| !write_emacs_trailer(out))
|
||||
success = FALSE;
|
||||
|
||||
/* Close the output stream */
|
||||
if (out && fclose(out))
|
||||
success = FALSE;
|
||||
|
||||
if (!success
|
||||
&& qof_backend_get_error(be) == ERR_BACKEND_NO_ERR) {
|
||||
|
||||
/* Use a generic write error code */
|
||||
qof_backend_set_error(be, ERR_FILEIO_WRITE_ERROR);
|
||||
}
|
||||
|
||||
gnc_book_write_accounts_to_xml_filehandle_v2 (be, book, out);
|
||||
|
||||
write_emacs_trailer(out);
|
||||
|
||||
if (fclose(out) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return success;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
@@ -106,9 +106,9 @@ typedef struct
|
||||
sixtp * (*create_parser) (void);
|
||||
gboolean (*add_item)(sixtp_gdv2 *, gpointer obj);
|
||||
int (*get_count) (QofBook *);
|
||||
void (*write) (FILE*, QofBook*);
|
||||
gboolean (*write) (FILE*, QofBook*);
|
||||
void (*scrub) (QofBook *);
|
||||
void (*ns) (FILE*);
|
||||
gboolean (*ns) (FILE*);
|
||||
} GncXmlDataType_t;
|
||||
|
||||
/**
|
||||
@@ -147,7 +147,7 @@ gboolean gnc_is_xml_data_file_v2(const gchar *name, gboolean *with_encoding);
|
||||
/** Write a name-space declaration for the provided namespace data type
|
||||
* within the GNC XML namespace at http://www.gnucash.org/XML.
|
||||
*/
|
||||
void gnc_xml2_write_namespace_decl (FILE *out, const char *namespace);
|
||||
gboolean gnc_xml2_write_namespace_decl (FILE *out, const char *namespace);
|
||||
|
||||
|
||||
typedef struct
|
||||
|
||||
@@ -45,13 +45,13 @@ static const gchar *emacs_trailer =
|
||||
"<!-- End: -->\n";
|
||||
|
||||
|
||||
void
|
||||
gboolean
|
||||
write_emacs_trailer(FILE *out)
|
||||
{
|
||||
fprintf(out, "%s", emacs_trailer);
|
||||
return fprintf(out, "%s", emacs_trailer) >= 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
write_one_account(FILE *out,
|
||||
Account *account,
|
||||
sixtp_gdv2 *gd,
|
||||
@@ -63,30 +63,43 @@ write_one_account(FILE *out,
|
||||
gnc_account_dom_tree_create(account, gd && gd->exporting, allow_incompat);
|
||||
|
||||
xmlElemDump(out, NULL, accnode);
|
||||
fprintf(out, "\n");
|
||||
|
||||
xmlFreeNode(accnode);
|
||||
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return FALSE;
|
||||
|
||||
gd->counter.accounts_loaded++;
|
||||
run_callback(gd, "account");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gboolean
|
||||
write_account_tree(FILE *out, Account *root, sixtp_gdv2 *gd)
|
||||
{
|
||||
GList *descendants, *node;
|
||||
gboolean allow_incompat = TRUE;
|
||||
gboolean success = TRUE;
|
||||
|
||||
if (allow_incompat)
|
||||
write_one_account(out, root, gd, allow_incompat);
|
||||
if (!write_one_account(out, root, gd, allow_incompat))
|
||||
return FALSE;
|
||||
|
||||
descendants = gnc_account_get_descendants(root);
|
||||
for (node = descendants; node; node = g_list_next(node))
|
||||
write_one_account(out, node->data, gd, allow_incompat);
|
||||
{
|
||||
if (!write_one_account(out, node->data, gd, allow_incompat))
|
||||
{
|
||||
success = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free(descendants);
|
||||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
gboolean
|
||||
write_accounts(FILE *out, QofBook *book, sixtp_gdv2 *gd)
|
||||
{
|
||||
write_account_tree(out, gnc_book_get_root_account(book), gd);
|
||||
return write_account_tree(out, gnc_book_get_root_account(book), gd);
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
#include "io-gncxml-v2.h"
|
||||
#include "qof.h"
|
||||
|
||||
void write_account_tree(FILE *out, Account *root, sixtp_gdv2 *gd);
|
||||
void write_accounts(FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
void write_book_parts(FILE *out, QofBook *book);
|
||||
void write_commodities(FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
gboolean write_account_tree(FILE *out, Account *root, sixtp_gdv2 *gd);
|
||||
gboolean write_accounts(FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
gboolean write_book_parts(FILE *out, QofBook *book);
|
||||
gboolean write_commodities(FILE *out, QofBook *book, sixtp_gdv2 *gd);
|
||||
|
||||
void write_emacs_trailer(FILE *out);
|
||||
gboolean write_emacs_trailer(FILE *out);
|
||||
|
||||
|
||||
#endif /* IO_UTILS_H */
|
||||
|
||||
@@ -210,11 +210,11 @@ gnc_dom_tree_to_address (xmlNodePtr node, GncAddress *address)
|
||||
return successful;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
address_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "addr");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "addr");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -503,16 +503,21 @@ xml_add_billterm (QofInstance *term_p, gpointer out_p)
|
||||
GncBillTerm *term = (GncBillTerm *) term_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
|
||||
node = billterm_dom_tree_create (term);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
billterm_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_billterm, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -707,13 +712,14 @@ billterm_scrub (QofBook *book)
|
||||
g_hash_table_destroy(ht);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
billterm_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "billterm");
|
||||
gnc_xml2_write_namespace_decl(out, "bt-days");
|
||||
gnc_xml2_write_namespace_decl(out, "bt-prox");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return
|
||||
gnc_xml2_write_namespace_decl(out, "billterm")
|
||||
&& gnc_xml2_write_namespace_decl(out, "bt-days")
|
||||
&& gnc_xml2_write_namespace_decl(out, "bt-prox");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -492,26 +492,30 @@ xml_add_customer (QofInstance * cust_p, gpointer out_p)
|
||||
GncCustomer *cust = (GncCustomer *) cust_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
if (!customer_should_be_saved (cust))
|
||||
return;
|
||||
|
||||
node = customer_dom_tree_create (cust);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
customer_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_customer, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
customer_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "cust");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "cust");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -417,26 +417,30 @@ xml_add_employee (QofInstance * employee_p, gpointer out_p)
|
||||
GncEmployee *employee = (GncEmployee *) employee_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
if (!employee_should_be_saved (employee))
|
||||
return;
|
||||
|
||||
node = employee_dom_tree_create (employee);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
employee_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_employee, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
employee_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "employee");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "employee");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -802,6 +802,9 @@ xml_add_entry (QofInstance * entry_p, gpointer out_p)
|
||||
GncEntry *entry = (GncEntry *) entry_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
|
||||
/* Don't save non-attached entries! */
|
||||
if (!(gncEntryGetOrder (entry) || gncEntryGetInvoice (entry) ||
|
||||
gncEntryGetBill (entry)))
|
||||
@@ -809,21 +812,23 @@ xml_add_entry (QofInstance * entry_p, gpointer out_p)
|
||||
|
||||
node = entry_dom_tree_create (entry);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
entry_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_entry, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
entry_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "entry");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "entry");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -523,26 +523,30 @@ xml_add_invoice (QofInstance * invoice_p, gpointer out_p)
|
||||
GncInvoice *invoice = (GncInvoice *) invoice_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
if (!invoice_should_be_saved (invoice))
|
||||
return;
|
||||
|
||||
node = invoice_dom_tree_create (invoice);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
invoice_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_invoice, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
invoice_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "invoice");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "invoice");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -310,26 +310,30 @@ xml_add_job (QofInstance * job_p, gpointer out_p)
|
||||
GncJob *job = (GncJob *) job_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
if (!job_should_be_saved (job))
|
||||
return;
|
||||
|
||||
node = job_dom_tree_create (job);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
job_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_job, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
job_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "job");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "job");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -353,26 +353,30 @@ xml_add_order (QofInstance * order_p, gpointer out_p)
|
||||
GncOrder *order = (GncOrder *) order_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
if (!order_should_be_saved (order))
|
||||
return;
|
||||
|
||||
node = order_dom_tree_create (order);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
order_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_order, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
order_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "order");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "order");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -208,11 +208,11 @@ gnc_dom_tree_to_owner (xmlNodePtr node, GncOwner *owner, QofBook *book)
|
||||
return successful;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
owner_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "owner");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "owner");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -466,16 +466,21 @@ xml_add_taxtable (QofInstance * table_p, gpointer out_p)
|
||||
GncTaxTable *table = (GncTaxTable *) table_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
|
||||
node = taxtable_dom_tree_create (table);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
taxtable_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_taxtable, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -659,12 +664,13 @@ taxtable_scrub (QofBook *book)
|
||||
g_hash_table_destroy(ht);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
taxtable_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "taxtable");
|
||||
gnc_xml2_write_namespace_decl(out, "tte");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return
|
||||
gnc_xml2_write_namespace_decl(out, "taxtable")
|
||||
&& gnc_xml2_write_namespace_decl(out, "tte");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -436,26 +436,30 @@ xml_add_vendor (QofInstance * vendor_p, gpointer out_p)
|
||||
GncVendor *vendor = (GncVendor *) vendor_p;
|
||||
FILE *out = out_p;
|
||||
|
||||
if (ferror(out))
|
||||
return;
|
||||
if (!vendor_should_be_saved (vendor))
|
||||
return;
|
||||
|
||||
node = vendor_dom_tree_create (vendor);
|
||||
xmlElemDump(out, NULL, node);
|
||||
fprintf(out, "\n");
|
||||
xmlFreeNode (node);
|
||||
if (ferror(out) || fprintf(out, "\n") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
vendor_write (FILE *out, QofBook *book)
|
||||
{
|
||||
qof_object_foreach (_GNC_MOD_NAME, book, xml_add_vendor, (gpointer) out);
|
||||
return ferror(out) == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
vendor_ns(FILE *out)
|
||||
{
|
||||
g_return_if_fail(out);
|
||||
gnc_xml2_write_namespace_decl(out, "vendor");
|
||||
g_return_val_if_fail(out, FALSE);
|
||||
return gnc_xml2_write_namespace_decl(out, "vendor");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user