Consistently include <config.h> in all C source files and never in header files.
[platform/upstream/dbus.git] / dbus / dbus-file-win.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-file-win.c windows related file implementation (internal to D-Bus implementation)
3  * 
4  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
5  * Copyright (C) 2003 CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #include <config.h>
26 #include "dbus-protocol.h"
27 #include "dbus-string.h"
28 #include "dbus-internals.h"
29 #include "dbus-sysdeps-win.h"
30 #include "dbus-pipe.h"
31
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <io.h>
35 #include <sys/stat.h>
36
37 #include <windows.h>
38 /**
39  * Appends the contents of the given file to the string,
40  * returning error code. At the moment, won't open a file
41  * more than a megabyte in size.
42  *
43  * @param str the string to append to
44  * @param filename filename to load
45  * @param error place to set an error
46  * @returns #FALSE if error was set
47  */
48 dbus_bool_t
49 _dbus_file_get_contents (DBusString       *str,
50                          const DBusString *filename,
51                          DBusError        *error)
52 {
53   int fd;
54   struct _stati64 sb;
55   int orig_len;
56   int total;
57   const char *filename_c;
58
59   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
60
61   filename_c = _dbus_string_get_const_data (filename);
62
63   fd = _open (filename_c, O_RDONLY | O_BINARY);
64   if (fd < 0)
65     {
66       dbus_set_error (error, _dbus_error_from_errno (errno),
67                       "Failed to open \"%s\": %s",
68                       filename_c,
69                       strerror (errno));
70       return FALSE;
71     }
72
73   _dbus_verbose ("file %s fd %d opened\n", filename_c, fd);
74
75   if (_fstati64 (fd, &sb) < 0)
76     {
77       dbus_set_error (error, _dbus_error_from_errno (errno),
78                       "Failed to stat \"%s\": %s",
79                       filename_c,
80                       strerror (errno));
81
82       _dbus_verbose ("fstat() failed: %s",
83                      strerror (errno));
84
85       _close (fd);
86
87       return FALSE;
88     }
89
90   if (sb.st_size > _DBUS_ONE_MEGABYTE)
91     {
92       dbus_set_error (error, DBUS_ERROR_FAILED,
93                       "File size %lu of \"%s\" is too large.",
94                       (unsigned long) sb.st_size, filename_c);
95       _close (fd);
96       return FALSE;
97     }
98
99   total = 0;
100   orig_len = _dbus_string_get_length (str);
101   if (sb.st_size > 0 && S_ISREG (sb.st_mode))
102     {
103       int bytes_read;
104
105       while (total < (int) sb.st_size)
106         {
107           bytes_read = _dbus_file_read (fd, str, sb.st_size - total);
108           if (bytes_read <= 0)
109             {
110               dbus_set_error (error, _dbus_error_from_errno (errno),
111                               "Error reading \"%s\": %s",
112                               filename_c,
113                               strerror (errno));
114
115               _dbus_verbose ("read() failed: %s",
116                              strerror (errno));
117
118               _close (fd);
119               _dbus_string_set_length (str, orig_len);
120               return FALSE;
121             }
122           else
123             total += bytes_read;
124         }
125
126       _close (fd);
127       return TRUE;
128     }
129   else if (sb.st_size != 0)
130     {
131       _dbus_verbose ("Can only open regular files at the moment.\n");
132       dbus_set_error (error, DBUS_ERROR_FAILED,
133                       "\"%s\" is not a regular file",
134                       filename_c);
135       _close (fd);
136       return FALSE;
137     }
138   else
139     {
140       _close (fd);
141       return TRUE;
142     }
143 }
144
145 /**
146  * Writes a string out to a file. If the file exists,
147  * it will be atomically overwritten by the new data.
148  *
149  * @param str the string to write out
150  * @param filename the file to save string to
151  * @param error error to be filled in on failure
152  * @returns #FALSE on failure
153  */
154 dbus_bool_t
155 _dbus_string_save_to_file (const DBusString *str,
156                            const DBusString *filename,
157                            DBusError        *error)
158 {
159   int fd;
160   int bytes_to_write;
161   const char *filename_c;
162   DBusString tmp_filename;
163   const char *tmp_filename_c;
164   int total;
165   const char *str_c;
166   dbus_bool_t need_unlink;
167   dbus_bool_t retval;
168
169   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
170
171   fd = -1;
172   retval = FALSE;
173   need_unlink = FALSE;
174
175   if (!_dbus_string_init (&tmp_filename))
176     {
177       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
178       return FALSE;
179     }
180
181   if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
182     {
183       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
184       _dbus_string_free (&tmp_filename);
185       return FALSE;
186     }
187
188   if (!_dbus_string_append (&tmp_filename, "."))
189     {
190       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
191       _dbus_string_free (&tmp_filename);
192       return FALSE;
193     }
194
195 #define N_TMP_FILENAME_RANDOM_BYTES 8
196   if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
197     {
198       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
199       _dbus_string_free (&tmp_filename);
200       return FALSE;
201     }
202
203   filename_c = _dbus_string_get_const_data (filename);
204   tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
205
206   fd = _open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
207               0600);
208   if (fd < 0)
209     {
210       dbus_set_error (error, _dbus_error_from_errno (errno),
211                       "Could not create %s: %s", tmp_filename_c,
212                       strerror (errno));
213       goto out;
214     }
215
216   _dbus_verbose ("tmp file %s fd %d opened\n", tmp_filename_c, fd);
217
218   need_unlink = TRUE;
219
220   total = 0;
221   bytes_to_write = _dbus_string_get_length (str);
222   str_c = _dbus_string_get_const_data (str);
223
224   while (total < bytes_to_write)
225     {
226       int bytes_written;
227
228       bytes_written = _write (fd, str_c + total, bytes_to_write - total);
229
230       if (bytes_written <= 0)
231         {
232           dbus_set_error (error, _dbus_error_from_errno (errno),
233                           "Could not write to %s: %s", tmp_filename_c,
234                           strerror (errno));
235           goto out;
236         }
237
238       total += bytes_written;
239     }
240
241   if (_close (fd) < 0)
242     {
243       dbus_set_error (error, _dbus_error_from_errno (errno),
244                       "Could not close file %s: %s",
245                       tmp_filename_c, strerror (errno));
246
247       goto out;
248     }
249
250   fd = -1;
251
252   /* Unlike rename(), MoveFileEx() can replace existing files */
253   if (!MoveFileExA (tmp_filename_c, filename_c, MOVEFILE_REPLACE_EXISTING))
254     {
255       char *emsg = _dbus_win_error_string (GetLastError ());
256       dbus_set_error (error, DBUS_ERROR_FAILED,
257                       "Could not rename %s to %s: %s",
258                       tmp_filename_c, filename_c,
259                       emsg);
260       _dbus_win_free_error_string (emsg);
261
262       goto out;
263     }
264
265   need_unlink = FALSE;
266
267   retval = TRUE;
268
269  out:
270   /* close first, then unlink */
271
272   if (fd >= 0)
273     _close (fd);
274
275   if (need_unlink && _unlink (tmp_filename_c) < 0)
276     _dbus_verbose ("failed to unlink temp file %s: %s\n",
277                    tmp_filename_c, strerror (errno));
278
279   _dbus_string_free (&tmp_filename);
280
281   if (!retval)
282     _DBUS_ASSERT_ERROR_IS_SET (error);
283
284   return retval;
285 }
286
287
288 /** Creates the given file, failing if the file already exists.
289  *
290  * @param filename the filename
291  * @param error error location
292  * @returns #TRUE if we created the file and it didn't exist
293  */
294 dbus_bool_t
295 _dbus_create_file_exclusively (const DBusString *filename,
296                                DBusError        *error)
297 {
298   int fd;
299   const char *filename_c;
300
301   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
302
303   filename_c = _dbus_string_get_const_data (filename);
304
305   fd = _open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
306               0600);
307   if (fd < 0)
308     {
309       dbus_set_error (error,
310                       DBUS_ERROR_FAILED,
311                       "Could not create file %s: %s\n",
312                       filename_c,
313                       strerror (errno));
314       return FALSE;
315     }
316
317   _dbus_verbose ("exclusive file %s fd %d opened\n", filename_c, fd);
318
319   if (_close (fd) < 0)
320     {
321       dbus_set_error (error,
322                       DBUS_ERROR_FAILED,
323                       "Could not close file %s: %s\n",
324                       filename_c,
325                       strerror (errno));
326       return FALSE;
327     }
328
329   return TRUE;
330 }
331
332 /**
333  * Thin wrapper around the read() system call that appends
334  * the data it reads to the DBusString buffer. It appends
335  * up to the given count, and returns the same value
336  * and same errno as read(). The only exception is that
337  * _dbus_file_read() handles EINTR for you. Also, 
338  * _dbus_file_read() can return ENOMEM.
339  * 
340  * @param fd the file descriptor to read from
341  * @param buffer the buffer to append data to
342  * @param count the amount of data to read
343  * @returns the number of bytes read or -1
344  */
345 int
346 _dbus_file_read (int               fd,
347                  DBusString       *buffer,
348                  int               count)
349 {
350   int bytes_read;
351   int start;
352   char *data;
353
354   _dbus_assert (count >= 0);
355
356   start = _dbus_string_get_length (buffer);
357
358   if (!_dbus_string_lengthen (buffer, count))
359     {
360       errno = ENOMEM;
361       return -1;
362     }
363
364   data = _dbus_string_get_data_len (buffer, start, count);
365
366  again:
367
368   bytes_read = _read (fd, data, count);
369
370   if (bytes_read < 0)
371     {
372       if (errno == EINTR)
373         goto again;
374       else
375         {
376           /* put length back (note that this doesn't actually realloc anything) */
377           _dbus_string_set_length (buffer, start);
378           return -1;
379         }
380     }
381   else
382     {
383       /* put length back (doesn't actually realloc) */
384       _dbus_string_set_length (buffer, start + bytes_read);
385
386 #if 0
387       if (bytes_read > 0)
388         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
389 #endif
390
391       return bytes_read;
392     }
393 }