D-Bus
1.4.10
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-file-win.c windows related file implementation (internal to D-Bus implementation) 00003 * 00004 * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. 00005 * Copyright (C) 2003 CodeFactory AB 00006 * 00007 * Licensed under the Academic Free License version 2.1 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 */ 00024 00025 #include <config.h> 00026 #include "dbus-protocol.h" 00027 #include "dbus-string.h" 00028 #include "dbus-internals.h" 00029 #include "dbus-sysdeps-win.h" 00030 #include "dbus-pipe.h" 00031 00032 #include <windows.h> 00033 00034 00046 static int 00047 _dbus_file_read (HANDLE hnd, 00048 DBusString *buffer, 00049 int count, 00050 DBusError *error) 00051 { 00052 BOOL result; 00053 DWORD bytes_read; 00054 int start; 00055 char *data; 00056 00057 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00058 00059 _dbus_assert (count >= 0); 00060 00061 start = _dbus_string_get_length (buffer); 00062 00063 if (!_dbus_string_lengthen (buffer, count)) 00064 { 00065 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00066 return -1; 00067 } 00068 00069 data = _dbus_string_get_data_len (buffer, start, count); 00070 00071 result = ReadFile (hnd, data, count, &bytes_read, NULL); 00072 if (result == 0) 00073 { 00074 char *emsg = _dbus_win_error_string (GetLastError ()); 00075 dbus_set_error (error, _dbus_win_error_from_last_error (), 00076 "Failed to read from 0x%x: %s", hnd, emsg); 00077 _dbus_win_free_error_string (emsg); 00078 return -1; 00079 } 00080 00081 if (bytes_read) 00082 { 00083 /* put length back (doesn't actually realloc) */ 00084 _dbus_string_set_length (buffer, start + bytes_read); 00085 00086 #if 0 00087 if (bytes_read > 0) 00088 _dbus_verbose_bytes_of_string (buffer, start, bytes_read); 00089 #endif 00090 } 00091 00092 return bytes_read; 00093 } 00094 00095 00106 dbus_bool_t 00107 _dbus_file_get_contents (DBusString *str, 00108 const DBusString *filename, 00109 DBusError *error) 00110 { 00111 HANDLE hnd; 00112 DWORD fsize; 00113 DWORD fsize_hi; 00114 int orig_len; 00115 unsigned int total; 00116 const char *filename_c; 00117 00118 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00119 00120 filename_c = _dbus_string_get_const_data (filename); 00121 00122 hnd = CreateFileA (filename_c, GENERIC_READ, 00123 FILE_SHARE_READ | FILE_SHARE_WRITE, 00124 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 00125 if (hnd == INVALID_HANDLE_VALUE) 00126 { 00127 char *emsg = _dbus_win_error_string (GetLastError ()); 00128 dbus_set_error (error, _dbus_win_error_from_last_error (), 00129 "Failed to open \"%s\": %s", filename_c, emsg); 00130 _dbus_win_free_error_string (emsg); 00131 return FALSE; 00132 } 00133 00134 _dbus_verbose ("file %s hnd %p opened\n", filename_c, hnd); 00135 00136 fsize = GetFileSize (hnd, &fsize_hi); 00137 if (fsize == 0xFFFFFFFF && GetLastError() != NO_ERROR) 00138 { 00139 char *emsg = _dbus_win_error_string (GetLastError ()); 00140 dbus_set_error (error, _dbus_win_error_from_last_error (), 00141 "Failed to get file size for \"%s\": %s", 00142 filename_c, emsg); 00143 _dbus_win_free_error_string (emsg); 00144 00145 _dbus_verbose ("GetFileSize() failed: %s", emsg); 00146 00147 CloseHandle (hnd); 00148 00149 return FALSE; 00150 } 00151 00152 if (fsize_hi != 0 || fsize > _DBUS_ONE_MEGABYTE) 00153 { 00154 dbus_set_error (error, DBUS_ERROR_FAILED, 00155 "File size %lu/%lu of \"%s\" is too large.", 00156 (unsigned long) fsize_hi, 00157 (unsigned long) fsize, filename_c); 00158 CloseHandle (hnd); 00159 return FALSE; 00160 } 00161 00162 total = 0; 00163 orig_len = _dbus_string_get_length (str); 00164 if (fsize > 0) 00165 { 00166 int bytes_read; 00167 00168 while (total < fsize) 00169 { 00170 bytes_read = _dbus_file_read (hnd, str, fsize - total, error); 00171 if (bytes_read <= 0) 00172 { 00173 if (bytes_read == 0) 00174 { 00175 dbus_set_error (error, DBUS_ERROR_FAILED, 00176 "Premature EOF reading \"%s\"", 00177 filename_c); 00178 } 00179 else 00180 _DBUS_ASSERT_ERROR_IS_SET (error); 00181 00182 CloseHandle (hnd); 00183 _dbus_string_set_length (str, orig_len); 00184 return FALSE; 00185 } 00186 else 00187 total += bytes_read; 00188 } 00189 00190 CloseHandle (hnd); 00191 return TRUE; 00192 } 00193 else 00194 { 00195 CloseHandle (hnd); 00196 return TRUE; 00197 } 00198 } 00199 00200 00211 dbus_bool_t 00212 _dbus_string_save_to_file (const DBusString *str, 00213 const DBusString *filename, 00214 dbus_bool_t world_readable, 00215 DBusError *error) 00216 { 00217 HANDLE hnd; 00218 int bytes_to_write; 00219 const char *filename_c; 00220 DBusString tmp_filename; 00221 const char *tmp_filename_c; 00222 int total; 00223 const char *str_c; 00224 dbus_bool_t need_unlink; 00225 dbus_bool_t retval; 00226 00227 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00228 00229 hnd = INVALID_HANDLE_VALUE; 00230 retval = FALSE; 00231 need_unlink = FALSE; 00232 00233 if (!_dbus_string_init (&tmp_filename)) 00234 { 00235 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00236 return FALSE; 00237 } 00238 00239 if (!_dbus_string_copy (filename, 0, &tmp_filename, 0)) 00240 { 00241 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00242 _dbus_string_free (&tmp_filename); 00243 return FALSE; 00244 } 00245 00246 if (!_dbus_string_append (&tmp_filename, ".")) 00247 { 00248 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00249 _dbus_string_free (&tmp_filename); 00250 return FALSE; 00251 } 00252 00253 #define N_TMP_FILENAME_RANDOM_BYTES 8 00254 if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES)) 00255 { 00256 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 00257 _dbus_string_free (&tmp_filename); 00258 return FALSE; 00259 } 00260 00261 filename_c = _dbus_string_get_const_data (filename); 00262 tmp_filename_c = _dbus_string_get_const_data (&tmp_filename); 00263 00264 /* TODO - support world-readable in an atomic fashion */ 00265 hnd = CreateFileA (tmp_filename_c, GENERIC_WRITE, 00266 FILE_SHARE_READ | FILE_SHARE_WRITE, 00267 NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 00268 INVALID_HANDLE_VALUE); 00269 if (hnd == INVALID_HANDLE_VALUE) 00270 { 00271 char *emsg = _dbus_win_error_string (GetLastError ()); 00272 dbus_set_error (error, _dbus_win_error_from_last_error (), 00273 "Could not create \"%s\": %s", filename_c, emsg); 00274 _dbus_win_free_error_string (emsg); 00275 goto out; 00276 } 00277 if (world_readable) 00278 { 00279 if (! _dbus_make_file_world_readable (&tmp_filename, error)) 00280 goto out; 00281 } 00282 00283 _dbus_verbose ("tmp file %s hnd %p opened\n", tmp_filename_c, hnd); 00284 00285 need_unlink = TRUE; 00286 00287 total = 0; 00288 bytes_to_write = _dbus_string_get_length (str); 00289 str_c = _dbus_string_get_const_data (str); 00290 00291 while (total < bytes_to_write) 00292 { 00293 DWORD bytes_written; 00294 BOOL res; 00295 00296 res = WriteFile (hnd, str_c + total, bytes_to_write - total, 00297 &bytes_written, NULL); 00298 00299 if (res == 0 || bytes_written <= 0) 00300 { 00301 char *emsg = _dbus_win_error_string (GetLastError ()); 00302 dbus_set_error (error, _dbus_win_error_from_last_error (), 00303 "Could not write to %s: %s", tmp_filename_c, emsg); 00304 _dbus_win_free_error_string (emsg); 00305 goto out; 00306 } 00307 00308 total += bytes_written; 00309 } 00310 00311 if (CloseHandle (hnd) == 0) 00312 { 00313 char *emsg = _dbus_win_error_string (GetLastError ()); 00314 dbus_set_error (error, _dbus_win_error_from_last_error (), 00315 "Could not close file %s: %s", tmp_filename_c, emsg); 00316 _dbus_win_free_error_string (emsg); 00317 goto out; 00318 } 00319 00320 hnd = INVALID_HANDLE_VALUE; 00321 00322 /* Unlike rename(), MoveFileEx() can replace existing files */ 00323 if (!MoveFileExA (tmp_filename_c, filename_c, MOVEFILE_REPLACE_EXISTING)) 00324 { 00325 char *emsg = _dbus_win_error_string (GetLastError ()); 00326 dbus_set_error (error, _dbus_win_error_from_last_error (), 00327 "Could not rename %s to %s: %s", 00328 tmp_filename_c, filename_c, emsg); 00329 _dbus_win_free_error_string (emsg); 00330 00331 goto out; 00332 } 00333 00334 need_unlink = FALSE; 00335 00336 retval = TRUE; 00337 00338 out: 00339 /* close first, then unlink */ 00340 00341 if (hnd != INVALID_HANDLE_VALUE) 00342 CloseHandle (hnd); 00343 00344 if (need_unlink && DeleteFileA (tmp_filename_c) == 0) 00345 { 00346 char *emsg = _dbus_win_error_string (GetLastError ()); 00347 _dbus_verbose ("Failed to unlink temp file %s: %s", tmp_filename_c, 00348 emsg); 00349 _dbus_win_free_error_string (emsg); 00350 } 00351 00352 _dbus_string_free (&tmp_filename); 00353 00354 if (!retval) 00355 _DBUS_ASSERT_ERROR_IS_SET (error); 00356 00357 return retval; 00358 } 00359 00360 00367 dbus_bool_t 00368 _dbus_create_file_exclusively (const DBusString *filename, 00369 DBusError *error) 00370 { 00371 HANDLE hnd; 00372 const char *filename_c; 00373 00374 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 00375 00376 filename_c = _dbus_string_get_const_data (filename); 00377 00378 hnd = CreateFileA (filename_c, GENERIC_WRITE, 00379 FILE_SHARE_READ | FILE_SHARE_WRITE, 00380 NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 00381 INVALID_HANDLE_VALUE); 00382 if (hnd == INVALID_HANDLE_VALUE) 00383 { 00384 char *emsg = _dbus_win_error_string (GetLastError ()); 00385 dbus_set_error (error, _dbus_win_error_from_last_error (), 00386 "Could not create file %s: %s", 00387 filename_c, emsg); 00388 _dbus_win_free_error_string (emsg); 00389 return FALSE; 00390 } 00391 00392 _dbus_verbose ("exclusive file %s hnd %p opened\n", filename_c, hnd); 00393 00394 if (CloseHandle (hnd) == 0) 00395 { 00396 char *emsg = _dbus_win_error_string (GetLastError ()); 00397 dbus_set_error (error, _dbus_win_error_from_last_error (), 00398 "Could not close file %s: %s", 00399 filename_c, emsg); 00400 _dbus_win_free_error_string (emsg); 00401 00402 return FALSE; 00403 } 00404 00405 return TRUE; 00406 } 00407