r18593 - gnucash/trunk/src - Bug #105669: Add checks to detect errors on write, especially if there no space left on the disk.

Andreas Köhler andi5 at code.gnucash.org
Sun Jan 31 13:37:28 EST 2010


Author: andi5
Date: 2010-01-31 13:37:28 -0500 (Sun, 31 Jan 2010)
New Revision: 18593
Trac: http://svn.gnucash.org/trac/changeset/18593

Modified:
   gnucash/trunk/src/backend/xml/gnc-backend-xml.c
   gnucash/trunk/src/backend/xml/gnc-book-xml-v2.c
   gnucash/trunk/src/backend/xml/io-gncxml-v2.c
   gnucash/trunk/src/backend/xml/io-gncxml-v2.h
   gnucash/trunk/src/backend/xml/io-utils.c
   gnucash/trunk/src/backend/xml/io-utils.h
   gnucash/trunk/src/business/business-core/xml/gnc-address-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-bill-term-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-customer-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-employee-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-entry-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-invoice-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-job-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-order-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-owner-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-tax-table-xml-v2.c
   gnucash/trunk/src/business/business-core/xml/gnc-vendor-xml-v2.c
Log:
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.

Modified: gnucash/trunk/src/backend/xml/gnc-backend-xml.c
===================================================================
--- gnucash/trunk/src/backend/xml/gnc-backend-xml.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/backend/xml/gnc-backend-xml.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -715,6 +715,9 @@
                   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("");

Modified: gnucash/trunk/src/backend/xml/gnc-book-xml-v2.c
===================================================================
--- gnucash/trunk/src/backend/xml/gnc-book-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/backend/xml/gnc-book-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -150,22 +150,18 @@
 /* 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 @@
         if (kvpnode)
         {
             xmlElemDump(out, NULL, kvpnode);
-            fprintf(out, "\n");
             xmlFreeNode(kvpnode);
+
+            if (ferror(out) || fprintf(out, "\n") < 0)
+                 return FALSE;
         }
     }
+
+    return TRUE;
 }
 
 

Modified: gnucash/trunk/src/backend/xml/io-gncxml-v2.c
===================================================================
--- gnucash/trunk/src/backend/xml/io-gncxml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/backend/xml/io-gncxml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -803,16 +803,17 @@
 
 /***********************************************************************/
 
-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 @@
              * '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");
+            xmlFreeNode(node);
 
-            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 @@
     }
 
     va_end(ap);
+    return success;
 }
 
 static gint
@@ -868,10 +878,10 @@
                        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 @@
     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 @@
 
     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 @@
         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 @@
                 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 @@
     }
 
     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 @@
 
     if (!node)
     {
-        return;
+        return TRUE;
     }
 
     xmlElemDump(out, NULL, node);
-    fprintf(out, "\n");
+    xmlFreeNode(node);
 
-    xmlFreeNode(node);
+    if (ferror(out) || fprintf(out, "\n") < 0)
+        return FALSE;
+
+    return TRUE;
 }
 
 static int
@@ -1049,27 +1075,30 @@
     node = gnc_transaction_dom_tree_create(t);
 
     xmlElemDump(be_data->out, NULL, node);
-    fprintf(be_data->out, "\n");
+    xmlFreeNode(node);
 
-    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 @@
     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 @@
 
     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 @@
     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 @@
     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,15 +1229,14 @@
 {
     QofBackend *be;
     sixtp_gdv2 *gd;
+    gboolean success = TRUE;
 
     if (!out) return FALSE;
 
-    write_v2_header (out);
+    if (!write_v2_header(out)
+        || !write_counts(out, "book", 1, NULL))
+        return FALSE;
 
-    write_counts(out,
-                 "book", 1,
-                 NULL);
-
     be = qof_book_get_backend(book);
     gd = gnc_sixtp_gdv2_new(book, FALSE, file_rw_feedback, be->percentage);
     gd->counter.commodities_total =
@@ -1204,12 +1249,12 @@
     gd->counter.budgets_total = qof_collection_count(
                                     qof_book_get_collection(book, GNC_ID_BUDGET));
 
-    write_book(out, book, gd);
+    if (!write_book(out, book, gd)
+        || fprintf(out, "</" GNC_V2_STRING ">\n\n") < 0)
+        success = FALSE;
 
-    fprintf(out, "</" GNC_V2_STRING ">\n\n");
-
     g_free(gd);
-    return TRUE;
+    return success;
 }
 
 /*
@@ -1222,6 +1267,7 @@
     Account *root;
     int ncom, nacc;
     sixtp_gdv2 *gd;
+    gboolean success = TRUE;
 
     if (!out) return FALSE;
 
@@ -1231,25 +1277,21 @@
     table = gnc_book_get_commodity_table(book);
     ncom = gnc_commodity_table_get_size(table);
 
-    write_v2_header (out);
+    if (!write_v2_header(out)
+        || !write_counts(out, "commodity", ncom, "account", nacc, NULL))
+        return FALSE;
 
-    write_counts(out,
-                 "commodity", ncom,
-                 "account", nacc,
-                 NULL);
-
     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);
+    if (!write_commodities(out, book, gd)
+        || !write_accounts(out, book, gd)
+        || fprintf(out, "</" GNC_V2_STRING ">\n\n") < 0)
+        success = FALSE;
 
-    write_accounts(out, book, gd);
-
-    fprintf(out, "</" GNC_V2_STRING ">\n\n");
-
     g_free(gd);
-    return TRUE;
+    return success;
 }
 
 #define BUFLEN 4096
@@ -1407,26 +1449,26 @@
     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 @@
     const char *filename)
 {
     FILE *out;
+    gboolean success = TRUE;
 
     out = g_fopen(filename, "w");
-    if (out == NULL)
-    {
-        return FALSE;
-    }
 
-    gnc_book_write_accounts_to_xml_filehandle_v2 (be, book, out);
+    /* 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;
 
-    write_emacs_trailer(out);
+    /* Close the output stream */
+    if (out && fclose(out))
+        success = FALSE;
 
-    if (fclose(out) != 0)
-    {
-        return 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);
     }
 
-    return TRUE;
+    return success;
 }
 
 /***********************************************************************/

Modified: gnucash/trunk/src/backend/xml/io-gncxml-v2.h
===================================================================
--- gnucash/trunk/src/backend/xml/io-gncxml-v2.h	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/backend/xml/io-gncxml-v2.h	2010-01-31 18:37:28 UTC (rev 18593)
@@ -106,9 +106,9 @@
     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 @@
 /** 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

Modified: gnucash/trunk/src/backend/xml/io-utils.c
===================================================================
--- gnucash/trunk/src/backend/xml/io-utils.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/backend/xml/io-utils.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -45,13 +45,13 @@
     "<!-- 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 @@
         gnc_account_dom_tree_create(account, gd && gd->exporting, allow_incompat);
 
     xmlElemDump(out, NULL, accnode);
-    fprintf(out, "\n");
+    xmlFreeNode(accnode);
 
-    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);
 }

Modified: gnucash/trunk/src/backend/xml/io-utils.h
===================================================================
--- gnucash/trunk/src/backend/xml/io-utils.h	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/backend/xml/io-utils.h	2010-01-31 18:37:28 UTC (rev 18593)
@@ -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 */

Modified: gnucash/trunk/src/business/business-core/xml/gnc-address-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-address-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-address-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -210,11 +210,11 @@
     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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-bill-term-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-bill-term-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-bill-term-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -503,16 +503,21 @@
   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 @@
   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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-customer-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-customer-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-customer-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -492,26 +492,30 @@
   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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-employee-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-employee-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-employee-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -417,26 +417,30 @@
   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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-entry-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-entry-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-entry-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -802,6 +802,9 @@
   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 @@
 
   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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-invoice-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-invoice-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-invoice-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -523,26 +523,30 @@
   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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-job-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-job-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-job-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -310,26 +310,30 @@
   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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-order-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-order-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-order-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -353,26 +353,30 @@
   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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-owner-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-owner-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-owner-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -208,11 +208,11 @@
     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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-tax-table-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-tax-table-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-tax-table-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -466,16 +466,21 @@
   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 @@
   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

Modified: gnucash/trunk/src/business/business-core/xml/gnc-vendor-xml-v2.c
===================================================================
--- gnucash/trunk/src/business/business-core/xml/gnc-vendor-xml-v2.c	2010-01-31 11:22:24 UTC (rev 18592)
+++ gnucash/trunk/src/business/business-core/xml/gnc-vendor-xml-v2.c	2010-01-31 18:37:28 UTC (rev 18593)
@@ -436,26 +436,30 @@
   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



More information about the gnucash-changes mailing list