D-Bus  1.13.7
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 
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  {
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 %p: %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 
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  {
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  {
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 
213  const DBusString *filename,
214  dbus_bool_t world_readable,
215  DBusError *error)
216 {
217  HANDLE hnd;
218  int bytes_to_write;
219  const char *filename_c;
220  DBusString tmp_filename;
221  const char *tmp_filename_c;
222  int total;
223  const char *str_c;
224  dbus_bool_t need_unlink;
225  dbus_bool_t retval;
226 
227  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
228 
229  hnd = INVALID_HANDLE_VALUE;
230  retval = FALSE;
231  need_unlink = FALSE;
232 
233  if (!_dbus_string_init (&tmp_filename))
234  {
236  return FALSE;
237  }
238 
239  if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
240  {
242  _dbus_string_free (&tmp_filename);
243  return FALSE;
244  }
245 
246  if (!_dbus_string_append (&tmp_filename, "."))
247  {
249  _dbus_string_free (&tmp_filename);
250  return FALSE;
251  }
252 
253 #define N_TMP_FILENAME_RANDOM_BYTES 8
254  if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES,
255  error))
256  {
257  _dbus_string_free (&tmp_filename);
258  return FALSE;
259  }
260 
261  filename_c = _dbus_string_get_const_data (filename);
262  tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
263 
264  /* TODO - support world-readable in an atomic fashion */
265  hnd = CreateFileA (tmp_filename_c, GENERIC_WRITE,
266  FILE_SHARE_READ | FILE_SHARE_WRITE,
267  NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,
268  INVALID_HANDLE_VALUE);
269  if (hnd == INVALID_HANDLE_VALUE)
270  {
271  char *emsg = _dbus_win_error_string (GetLastError ());
272  dbus_set_error (error, _dbus_win_error_from_last_error (),
273  "Could not create \"%s\": %s", filename_c, emsg);
274  _dbus_win_free_error_string (emsg);
275  goto out;
276  }
277  if (world_readable)
278  {
279  if (! _dbus_make_file_world_readable (&tmp_filename, error))
280  goto out;
281  }
282 
283  _dbus_verbose ("tmp file %s hnd %p opened\n", tmp_filename_c, hnd);
284 
285  need_unlink = TRUE;
286 
287  total = 0;
288  bytes_to_write = _dbus_string_get_length (str);
289  str_c = _dbus_string_get_const_data (str);
290 
291  while (total < bytes_to_write)
292  {
293  DWORD bytes_written;
294  BOOL res;
295 
296  res = WriteFile (hnd, str_c + total, bytes_to_write - total,
297  &bytes_written, NULL);
298 
299  if (res == 0 || bytes_written <= 0)
300  {
301  char *emsg = _dbus_win_error_string (GetLastError ());
302  dbus_set_error (error, _dbus_win_error_from_last_error (),
303  "Could not write to %s: %s", tmp_filename_c, emsg);
304  _dbus_win_free_error_string (emsg);
305  goto out;
306  }
307 
308  total += bytes_written;
309  }
310 
311  if (CloseHandle (hnd) == 0)
312  {
313  char *emsg = _dbus_win_error_string (GetLastError ());
314  dbus_set_error (error, _dbus_win_error_from_last_error (),
315  "Could not close file %s: %s", tmp_filename_c, emsg);
316  _dbus_win_free_error_string (emsg);
317  goto out;
318  }
319 
320  hnd = INVALID_HANDLE_VALUE;
321 
322  /* Unlike rename(), MoveFileEx() can replace existing files */
323  if (!MoveFileExA (tmp_filename_c, filename_c, MOVEFILE_REPLACE_EXISTING))
324  {
325  char *emsg = _dbus_win_error_string (GetLastError ());
326  dbus_set_error (error, _dbus_win_error_from_last_error (),
327  "Could not rename %s to %s: %s",
328  tmp_filename_c, filename_c, emsg);
329  _dbus_win_free_error_string (emsg);
330 
331  goto out;
332  }
333 
334  need_unlink = FALSE;
335 
336  retval = TRUE;
337 
338  out:
339  /* close first, then unlink */
340 
341  if (hnd != INVALID_HANDLE_VALUE)
342  CloseHandle (hnd);
343 
344  if (need_unlink && DeleteFileA (tmp_filename_c) == 0)
345  {
346  char *emsg = _dbus_win_error_string (GetLastError ());
347  _dbus_verbose ("Failed to unlink temp file %s: %s", tmp_filename_c,
348  emsg);
349  _dbus_win_free_error_string (emsg);
350  }
351 
352  _dbus_string_free (&tmp_filename);
353 
354  if (!retval)
355  _DBUS_ASSERT_ERROR_IS_SET (error);
356 
357  return retval;
358 }
359 
360 
369  DBusError *error)
370 {
371  HANDLE hnd;
372  const char *filename_c;
373 
374  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
375 
376  filename_c = _dbus_string_get_const_data (filename);
377 
378  hnd = CreateFileA (filename_c, GENERIC_WRITE,
379  FILE_SHARE_READ | FILE_SHARE_WRITE,
380  NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,
381  INVALID_HANDLE_VALUE);
382  if (hnd == INVALID_HANDLE_VALUE)
383  {
384  char *emsg = _dbus_win_error_string (GetLastError ());
385  dbus_set_error (error, _dbus_win_error_from_last_error (),
386  "Could not create file %s: %s",
387  filename_c, emsg);
388  _dbus_win_free_error_string (emsg);
389  return FALSE;
390  }
391 
392  _dbus_verbose ("exclusive file %s hnd %p opened\n", filename_c, hnd);
393 
394  if (CloseHandle (hnd) == 0)
395  {
396  char *emsg = _dbus_win_error_string (GetLastError ());
397  dbus_set_error (error, _dbus_win_error_from_last_error (),
398  "Could not close file %s: %s",
399  filename_c, emsg);
400  _dbus_win_free_error_string (emsg);
401 
402  return FALSE;
403  }
404 
405  return TRUE;
406 }
407 
dbus_bool_t _dbus_string_append(DBusString *str, const char *buffer)
Appends a nul-terminated C-style string to a DBusString.
Definition: dbus-string.c:952
#define NULL
A null pointer, defined appropriately for C or C++.
dbus_bool_t _dbus_create_file_exclusively(const DBusString *filename, DBusError *error)
Creates the given file, failing if the file already exists.
dbus_bool_t _dbus_string_lengthen(DBusString *str, int additional_length)
Makes a string longer by the given number of bytes.
Definition: dbus-string.c:777
dbus_bool_t _dbus_string_save_to_file(const DBusString *str, const DBusString *filename, dbus_bool_t world_readable, DBusError *error)
Writes a string out to a file.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
dbus_bool_t _dbus_file_get_contents(DBusString *str, const DBusString *filename, DBusError *error)
Appends the contents of the given file to the string, returning error code.
char * _dbus_string_get_data_len(DBusString *str, int start, int len)
Gets a sub-portion of the raw character buffer from the string.
Definition: dbus-string.c:507
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
dbus_bool_t _dbus_string_copy(const DBusString *source, int start, DBusString *dest, int insert_at)
Like _dbus_string_move(), but does not delete the section of the source string that&#39;s copied to the d...
Definition: dbus-string.c:1300
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
dbus_bool_t _dbus_generate_random_ascii(DBusString *str, int n_bytes, DBusError *error)
Generates the given number of random bytes, where the bytes are chosen from the alphanumeric ASCII su...
Definition: dbus-sysdeps.c:559
dbus_bool_t _dbus_make_file_world_readable(const DBusString *filename, DBusError *error)
Makes the file readable by every user in the system.
Object representing an exception.
Definition: dbus-errors.h:48
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:354
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init(), and fills it with the same contents as #_DBUS_STRING_I...
Definition: dbus-string.c:264
#define TRUE
Expands to "1".
#define DBUS_ERROR_FAILED
A generic error; "something went wrong" - see the error message for more.
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
#define FALSE
Expands to "0".
dbus_bool_t _dbus_string_set_length(DBusString *str, int length)
Sets the length of a string.
Definition: dbus-string.c:819
DBUS_PRIVATE_EXPORT void _dbus_verbose_bytes_of_string(const DBusString *str, int start, int len)
Dump the given part of the string to verbose log.