diff options
-rw-r--r-- | filter/ChangeLog | 8 | ||||
-rw-r--r-- | filter/rule-context.c | 313 |
2 files changed, 317 insertions, 4 deletions
diff --git a/filter/ChangeLog b/filter/ChangeLog index 1c24bc393b..c1b4f2d613 100644 --- a/filter/ChangeLog +++ b/filter/ChangeLog @@ -1,3 +1,11 @@ +2002-08-05 Jeffrey Stedfast <fejj@ximian.com> + + * rule-context.c (xml_doc_save): New internal function to replace + xmlSaveFile. Does proper error checking and so forth to ensure + that the resulting file does not ever get truncated. + (save): Cal xml_doc_save rather than xmlSaveFile. Fixes bug + #25980. + 2002-08-02 Not Zed <NotZed@Ximian.com> * filter.glade: Added a datespec editor window. diff --git a/filter/rule-context.c b/filter/rule-context.c index 490c169d05..03f89b8c71 100644 --- a/filter/rule-context.c +++ b/filter/rule-context.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2000 Ximian Inc. * @@ -18,6 +19,7 @@ * Boston, MA 02111-1307, USA. */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -26,8 +28,13 @@ #include <alloca.h> #endif -#include <errno.h> #include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + #include <gtk/gtksignal.h> #include <libgnomeui/gnome-dialog.h> #include <libgnomeui/gnome-stock.h> @@ -374,6 +381,304 @@ rule_context_save (RuleContext *f, const char *user) return ((RuleContextClass *) ((GtkObject *) f)->klass)->save(f, user); } + +static void xmlNodeDump (xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format); + + +static void +xmlAttrDump (xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) +{ + xmlChar *value; + + if (cur == NULL) { +#ifdef DEBUG_TREE + fprintf(stderr, "xmlAttrDump : property == NULL\n"); +#endif + return; + } + + xmlBufferWriteChar (buf, " "); + if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { + xmlBufferWriteCHAR (buf, cur->ns->prefix); + xmlBufferWriteChar (buf, ":"); + } + + xmlBufferWriteCHAR (buf, cur->name); + value = xmlNodeListGetString (doc, cur->val, 0); + if (value) { + xmlBufferWriteChar (buf, "="); + xmlBufferWriteQuotedString (buf, value); + xmlFree (value); + } else { + xmlBufferWriteChar (buf, "=\"\""); + } +} + +static void +xmlAttrListDump (xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) +{ + if (cur == NULL) { +#ifdef DEBUG_TREE + fprintf(stderr, "xmlAttrListDump : property == NULL\n"); +#endif + return; + } + + while (cur != NULL) { + xmlAttrDump (buf, doc, cur); + cur = cur->next; + } +} + +static void +xmlNodeListDump (xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format) +{ + int i; + + if (cur == NULL) { +#ifdef DEBUG_TREE + fprintf(stderr, "xmlNodeListDump : node == NULL\n"); +#endif + return; + } + + while (cur != NULL) { + if ((format) && (xmlIndentTreeOutput) && + (cur->type == XML_ELEMENT_NODE)) + for (i = 0; i < level; i++) + xmlBufferWriteChar (buf, " "); + xmlNodeDump (buf, doc, cur, level, format); + if (format) { + xmlBufferWriteChar (buf, "\n"); + } + cur = cur->next; + } +} + +static void +xmlNodeDump (xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, int format) +{ + int i; + xmlNodePtr tmp; + + if (cur == NULL) { +#ifdef DEBUG_TREE + fprintf(stderr, "xmlNodeDump : node == NULL\n"); +#endif + return; + } + + if (cur->type == XML_TEXT_NODE) { + if (cur->content != NULL) { + xmlChar *buffer; + +#ifndef XML_USE_BUFFER_CONTENT + buffer = xmlEncodeEntitiesReentrant (doc, cur->content); +#else + buffer = xmlEncodeEntitiesReentrant (doc, xmlBufferContent (cur->content)); +#endif + if (buffer != NULL) { + xmlBufferWriteCHAR (buf, buffer); + xmlFree (buffer); + } + } + return; + } + + if (cur->type == XML_PI_NODE) { + if (cur->content != NULL) { + xmlBufferWriteChar (buf, "<?"); + xmlBufferWriteCHAR (buf, cur->name); + if (cur->content != NULL) { + xmlBufferWriteChar (buf, " "); +#ifndef XML_USE_BUFFER_CONTENT + xmlBufferWriteCHAR (buf, cur->content); +#else + xmlBufferWriteCHAR (buf, xmlBufferContent (cur->content)); +#endif + } + xmlBufferWriteChar (buf, "?>"); + } + return; + } + + if (cur->type == XML_COMMENT_NODE) { + if (cur->content != NULL) { + xmlBufferWriteChar (buf, "<!--"); +#ifndef XML_USE_BUFFER_CONTENT + xmlBufferWriteCHAR (buf, cur->content); +#else + xmlBufferWriteCHAR (buf, xmlBufferContent (cur->content)); +#endif + xmlBufferWriteChar (buf, "-->"); + } + return; + } + + if (cur->type == XML_ENTITY_REF_NODE) { + xmlBufferWriteChar (buf, "&"); + xmlBufferWriteCHAR (buf, cur->name); + xmlBufferWriteChar (buf, ";"); + return; + } + + if (cur->type == XML_CDATA_SECTION_NODE) { + xmlBufferWriteChar (buf, "<![CDATA["); + if (cur->content != NULL) +#ifndef XML_USE_BUFFER_CONTENT + xmlBufferWriteCHAR (buf, cur->content); +#else + xmlBufferWriteCHAR (buf, xmlBufferContent(cur->content)); +#endif + xmlBufferWriteChar (buf, "]]>"); + return; + } + + if (format == 1) { + tmp = cur->childs; + while (tmp != NULL) { + if ((tmp->type == XML_TEXT_NODE) || + (tmp->type == XML_ENTITY_REF_NODE)) { + format = 0; + break; + } + tmp = tmp->next; + } + } + + xmlBufferWriteChar (buf, "<"); + if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { + xmlBufferWriteCHAR (buf, cur->ns->prefix); + xmlBufferWriteChar (buf, ":"); + } + + xmlBufferWriteCHAR (buf, cur->name); + + if (cur->properties != NULL) + xmlAttrListDump (buf, doc, cur->properties); + + if ((cur->content == NULL) && (cur->childs == NULL) && + (!xmlSaveNoEmptyTags)) { + xmlBufferWriteChar (buf, "/>"); + return; + } + + xmlBufferWriteChar (buf, ">"); + if (cur->content != NULL) { + xmlChar *buffer; + +#ifndef XML_USE_BUFFER_CONTENT + buffer = xmlEncodeEntitiesReentrant (doc, cur->content); +#else + buffer = xmlEncodeEntitiesReentrant (doc, xmlBufferContent (cur->content)); +#endif + if (buffer != NULL) { + xmlBufferWriteCHAR (buf, buffer); + xmlFree (buffer); + } + } + + if (cur->childs != NULL) { + if (format) + xmlBufferWriteChar (buf, "\n"); + + xmlNodeListDump (buf, doc, cur->childs, (level >= 0 ? level + 1 : -1), format); + if ((xmlIndentTreeOutput) && (format)) + for (i = 0; i < level; i++) + xmlBufferWriteChar (buf, " "); + } + + xmlBufferWriteChar (buf, "</"); + if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) { + xmlBufferWriteCHAR (buf, cur->ns->prefix); + xmlBufferWriteChar (buf, ":"); + } + + xmlBufferWriteCHAR (buf, cur->name); + xmlBufferWriteChar (buf, ">"); +} + +static void +xmlDocContentDump (xmlBufferPtr buf, xmlDocPtr cur) +{ + xmlBufferWriteChar (buf, "<?xml version="); + + if (cur->version != NULL) + xmlBufferWriteQuotedString (buf, cur->version); + else + xmlBufferWriteChar (buf, "\"1.0\""); + + if ((cur->encoding != NULL) && + (strcasecmp (cur->encoding, "UTF-8") != 0)) { + xmlBufferWriteChar (buf, " encoding="); + xmlBufferWriteQuotedString (buf, cur->encoding); + } + + switch (cur->standalone) { + case 1: + xmlBufferWriteChar (buf, " standalone=\"yes\""); + break; + } + + xmlBufferWriteChar (buf, "?>\n"); + if (cur->root != NULL) { + xmlNodePtr child = cur->root; + + while (child != NULL) { + xmlNodeDump (buf, cur, child, 0, 1); + xmlBufferWriteChar (buf, "\n"); + child = child->next; + } + } +} + +static int +xml_doc_save (xmlDocPtr doc, const char *filename) +{ + size_t n, written = 0; + xmlBufferPtr buf; + int errnosave; + ssize_t w; + int fd; + + fd = open (filename, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd == -1) + return -1; + + if (!(buf = xmlBufferCreate ())) { + close (fd); + unlink (filename); + errno = ENOMEM; + return -1; + } + + xmlDocContentDump (buf, doc); + + n = buf->use; + do { + do { + w = write (fd, buf->content + written, n - written); + } while (w == -1 && errno == EINTR); + + if (w > 0) + written += w; + } while (w != -1 && written < n); + + xmlBufferFree (buf); + + if (written < n || fsync (fd) == -1) { + errnosave = errno; + close (fd); + unlink (filename); + errno = errnosave; + return -1; + } + + close (fd); + + return 0; +} + static int save (RuleContext *f, const char *user) { @@ -384,7 +689,7 @@ save (RuleContext *f, const char *user) struct _rule_set_map *map; char *usersav, *userbak, *slash; int ret; - + doc = xmlNewDoc ("1.0"); root = xmlNewDocNode (doc, NULL, "filteroptions", NULL); xmlDocSetRootElement (doc, root); @@ -401,7 +706,7 @@ save (RuleContext *f, const char *user) } l = g_list_next (l); } - + usersav = alloca(strlen(user)+5); userbak = alloca(strlen(user)+5); slash = strrchr(user, '/'); @@ -411,7 +716,7 @@ save (RuleContext *f, const char *user) sprintf(usersav, ".#%s", user); sprintf(userbak, "%s~", user); printf("saving rules to '%s' then backup '%s'\n", usersav, userbak); - ret = xmlSaveFile(usersav, doc); + ret = xml_doc_save (doc, usersav); if (ret != -1) { rename(user, userbak); ret = rename(usersav, user); |