goa: Add missing linker flag (for real).
[platform/upstream/evolution-data-server.git] / libedataserver / e-xml-utils.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU Lesser General Public
7  * License as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include <config.h>
21
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25
26 #ifndef O_BINARY
27 #define O_BINARY 0
28 #endif
29
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
32
33 #include <glib/gstdio.h>
34
35 #include "e-xml-utils.h"
36
37 #ifdef G_OS_WIN32
38 #define fsync(fd) 0
39 #endif
40
41 /**
42  * e_xml_parse_file:
43  * @filename: path to an XML file
44  *
45  * Reads a local XML file and parses the contents into an XML document
46  * structure.  If the XML file cannot be read or its contents are malformed,
47  * the function returns %NULL.
48  *
49  * Returns: an XML document structure, or %NULL
50  **/
51 xmlDocPtr
52 e_xml_parse_file (const gchar *filename)
53 {
54         xmlDocPtr result = NULL;
55
56         GMappedFile *mapped_file;
57
58         mapped_file = g_mapped_file_new (filename, FALSE, NULL);
59         if (mapped_file) {
60                 result = xmlParseMemory (
61                         g_mapped_file_get_contents (mapped_file),
62                         g_mapped_file_get_length (mapped_file));
63                 g_mapped_file_unref (mapped_file);
64         }
65
66         return result;
67 }
68
69 /**
70  * e_xml_save_file:
71  * @filename: path to a file to save to
72  * @doc: an XML document structure
73  *
74  * Writes the given XML document structure to the file given by @filename.
75  * If an error occurs while saving, the function returns -1 and sets errno.
76  *
77  * Returns: 0 on success, -1 on failure
78  **/
79 gint
80 e_xml_save_file (const gchar *filename,
81                  xmlDocPtr doc)
82 {
83         gchar *filesave;
84         xmlChar *xmlbuf;
85         gsize n, written = 0;
86         gint ret, fd, size;
87         gint errnosave;
88         gssize w;
89         gchar *dirname = g_path_get_dirname (filename);
90         gchar *basename = g_path_get_basename (filename);
91         gchar *savebasename = g_strconcat (".#", basename, NULL);
92
93         g_free (basename);
94         filesave = g_build_filename (dirname, savebasename, NULL);
95         g_free (savebasename);
96         g_free (dirname);
97
98         fd = g_open (filesave, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600);
99         if (fd == -1) {
100                 g_free (filesave);
101                 return -1;
102         }
103
104         xmlDocDumpFormatMemory (doc, &xmlbuf, &size, TRUE);
105         if (size <= 0) {
106                 close (fd);
107                 g_unlink (filesave);
108                 g_free (filesave);
109                 errno = ENOMEM;
110                 return -1;
111         }
112
113         n = (gsize) size;
114         do {
115                 do {
116                         w = write (fd, xmlbuf + written, n - written);
117                 } while (w == -1 && errno == EINTR);
118
119                 if (w > 0)
120                         written += w;
121         } while (w != -1 && written < n);
122
123         xmlFree (xmlbuf);
124
125         if (written < n || fsync (fd) == -1) {
126                 errnosave = errno;
127                 close (fd);
128                 g_unlink (filesave);
129                 g_free (filesave);
130                 errno = errnosave;
131                 return -1;
132         }
133
134         while ((ret = close (fd)) == -1 && errno == EINTR)
135                 ;
136
137         if (ret == -1) {
138                 g_free (filesave);
139                 return -1;
140         }
141
142         if (g_rename (filesave, filename) == -1) {
143                 errnosave = errno;
144                 g_unlink (filesave);
145                 g_free (filesave);
146                 errno = errnosave;
147                 return -1;
148         }
149         g_free (filesave);
150
151         return 0;
152 }
153
154 /**
155  * e_xml_get_child_by_name:
156  * @parent: an XML node structure
157  * @child_name: element name of a child node
158  *
159  * Attempts to find a child element of @parent named @child_name.
160  * If no such child exists, the function returns %NULL.
161  *
162  * Returns: a child XML node structure, or %NULL
163  **/
164 xmlNode *
165 e_xml_get_child_by_name (const xmlNode *parent,
166                          const xmlChar *child_name)
167 {
168         xmlNode *child;
169
170         g_return_val_if_fail (parent != NULL, NULL);
171         g_return_val_if_fail (child_name != NULL, NULL);
172
173         for (child = parent->xmlChildrenNode; child != NULL; child = child->next) {
174                 if (xmlStrcmp (child->name, child_name) == 0) {
175                         return child;
176                 }
177         }
178         return NULL;
179 }
180