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