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