1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2/* dbus-file-unix.c unix 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 27#include "dbus-protocol.h" 28#include "dbus-errors.h" 29#include "dbus-file.h" 30#include "dbus-internals.h" 31#include "dbus-sysdeps.h" 32#include "dbus-sysdeps-unix.h" 33 34#include <sys/stat.h> 35#include <stdio.h> 36#include <fcntl.h> 37#include <unistd.h> 38#include <errno.h> 39 40#ifndef O_BINARY 41#define O_BINARY 0 42#endif 43 44/** 45 * Appends the contents of the given file to the string, 46 * returning error code. At the moment, won't open a file 47 * more than a megabyte in size. 48 * 49 * @param str the string to append to 50 * @param filename filename to load 51 * @param error place to set an error 52 * @returns #FALSE if error was set 53 */ 54dbus_bool_t 55_dbus_file_get_contents (DBusString *str, 56 const DBusString *filename, 57 DBusError *error) 58{ 59 int fd; 60 struct stat sb; 61 int orig_len; 62 int total; 63 const char *filename_c; 64 65 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 66 67 filename_c = _dbus_string_get_const_data (filename); 68 69 /* O_BINARY useful on Cygwin */ 70 fd = open (filename_c, O_RDONLY | O_BINARY); 71 if (fd < 0) 72 { 73 dbus_set_error (error, _dbus_error_from_errno (errno), 74 "Failed to open \"%s\": %s", 75 filename_c, 76 _dbus_strerror (errno)); 77 return FALSE; 78 } 79 80 _dbus_verbose ("file fd %d opened\n", fd); 81 82 if (fstat (fd, &sb) < 0) 83 { 84 dbus_set_error (error, _dbus_error_from_errno (errno), 85 "Failed to stat \"%s\": %s", 86 filename_c, 87 _dbus_strerror (errno)); 88 89 _dbus_verbose ("fstat() failed: %s", 90 _dbus_strerror (errno)); 91 92 _dbus_close (fd, NULL); 93 94 return FALSE; 95 } 96 97 if (sb.st_size > _DBUS_ONE_MEGABYTE) 98 { 99 dbus_set_error (error, DBUS_ERROR_FAILED, 100 "File size %lu of \"%s\" is too large.", 101 (unsigned long) sb.st_size, filename_c); 102 _dbus_close (fd, NULL); 103 return FALSE; 104 } 105 106 total = 0; 107 orig_len = _dbus_string_get_length (str); 108 if (sb.st_size > 0 && S_ISREG (sb.st_mode)) 109 { 110 int bytes_read; 111 112 while (total < (int) sb.st_size) 113 { 114 bytes_read = _dbus_read (fd, str, 115 sb.st_size - total); 116 if (bytes_read <= 0) 117 { 118 dbus_set_error (error, _dbus_error_from_errno (errno), 119 "Error reading \"%s\": %s", 120 filename_c, 121 _dbus_strerror (errno)); 122 123 _dbus_verbose ("read() failed: %s", 124 _dbus_strerror (errno)); 125 126 _dbus_close (fd, NULL); 127 _dbus_string_set_length (str, orig_len); 128 return FALSE; 129 } 130 else 131 total += bytes_read; 132 } 133 134 _dbus_close (fd, NULL); 135 return TRUE; 136 } 137 else if (sb.st_size != 0) 138 { 139 _dbus_verbose ("Can only open regular files at the moment.\n"); 140 dbus_set_error (error, DBUS_ERROR_FAILED, 141 "\"%s\" is not a regular file", 142 filename_c); 143 _dbus_close (fd, NULL); 144 return FALSE; 145 } 146 else 147 { 148 _dbus_close (fd, NULL); 149 return TRUE; 150 } 151} 152 153/** 154 * Writes a string out to a file. If the file exists, 155 * it will be atomically overwritten by the new data. 156 * 157 * @param str the string to write out 158 * @param filename the file to save string to 159 * @param world_readable If set, ensure the file is world readable 160 * @param error error to be filled in on failure 161 * @returns #FALSE on failure 162 */ 163dbus_bool_t 164_dbus_string_save_to_file (const DBusString *str, 165 const DBusString *filename, 166 dbus_bool_t world_readable, 167 DBusError *error) 168{ 169 int fd; 170 int bytes_to_write; 171 const char *filename_c; 172 DBusString tmp_filename; 173 const char *tmp_filename_c; 174 int total; 175 dbus_bool_t need_unlink; 176 dbus_bool_t retval; 177 178 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 179 180 fd = -1; 181 retval = FALSE; 182 need_unlink = FALSE; 183 184 if (!_dbus_string_init (&tmp_filename)) 185 { 186 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 187 return FALSE; 188 } 189 190 if (!_dbus_string_copy (filename, 0, &tmp_filename, 0)) 191 { 192 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 193 _dbus_string_free (&tmp_filename); 194 return FALSE; 195 } 196 197 if (!_dbus_string_append (&tmp_filename, ".")) 198 { 199 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 200 _dbus_string_free (&tmp_filename); 201 return FALSE; 202 } 203 204#define N_TMP_FILENAME_RANDOM_BYTES 8 205 if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES)) 206 { 207 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); 208 _dbus_string_free (&tmp_filename); 209 return FALSE; 210 } 211 212 filename_c = _dbus_string_get_const_data (filename); 213 tmp_filename_c = _dbus_string_get_const_data (&tmp_filename); 214 215 fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, 216 world_readable ? 0644 : 0600); 217 if (fd < 0) 218 { 219 dbus_set_error (error, _dbus_error_from_errno (errno), 220 "Could not create %s: %s", tmp_filename_c, 221 _dbus_strerror (errno)); 222 goto out; 223 } 224 if (world_readable) 225 { 226 /* Ensure the file is world readable even in the presence of 227 * possibly restrictive umasks; 228 * see http://lists.freedesktop.org/archives/dbus/2010-September/013367.html 229 */ 230 if (fchmod (fd, 0644) < 0) 231 { 232 dbus_set_error (error, _dbus_error_from_errno (errno), 233 "Could not chmod %s: %s", tmp_filename_c, 234 _dbus_strerror (errno)); 235 goto out; 236 } 237 } 238 239 _dbus_verbose ("tmp file fd %d opened\n", fd); 240 241 need_unlink = TRUE; 242 243 total = 0; 244 bytes_to_write = _dbus_string_get_length (str); 245 246 while (total < bytes_to_write) 247 { 248 int bytes_written; 249 250 bytes_written = _dbus_write (fd, str, total, 251 bytes_to_write - total); 252 253 if (bytes_written <= 0) 254 { 255 dbus_set_error (error, _dbus_error_from_errno (errno), 256 "Could not write to %s: %s", tmp_filename_c, 257 _dbus_strerror (errno)); 258 259 goto out; 260 } 261 262 total += bytes_written; 263 } 264 265 if (fsync(fd)) 266 { 267 dbus_set_error (error, _dbus_error_from_errno (errno), 268 "Could not synchronize file %s: %s", 269 tmp_filename_c, _dbus_strerror (errno)); 270 271 goto out; 272 } 273 274 if (!_dbus_close (fd, NULL)) 275 { 276 dbus_set_error (error, _dbus_error_from_errno (errno), 277 "Could not close file %s: %s", 278 tmp_filename_c, _dbus_strerror (errno)); 279 280 goto out; 281 } 282 283 fd = -1; 284 285 if (rename (tmp_filename_c, filename_c) < 0) 286 { 287 dbus_set_error (error, _dbus_error_from_errno (errno), 288 "Could not rename %s to %s: %s", 289 tmp_filename_c, filename_c, 290 _dbus_strerror (errno)); 291 292 goto out; 293 } 294 295 need_unlink = FALSE; 296 297 retval = TRUE; 298 299 out: 300 /* close first, then unlink, to prevent ".nfs34234235" garbage 301 * files 302 */ 303 304 if (fd >= 0) 305 _dbus_close (fd, NULL); 306 307 if (need_unlink && unlink (tmp_filename_c) < 0) 308 _dbus_verbose ("Failed to unlink temp file %s: %s\n", 309 tmp_filename_c, _dbus_strerror (errno)); 310 311 _dbus_string_free (&tmp_filename); 312 313 if (!retval) 314 _DBUS_ASSERT_ERROR_IS_SET (error); 315 316 return retval; 317} 318 319/** Makes the file readable by every user in the system. 320 * 321 * @param filename the filename 322 * @param error error location 323 * @returns #TRUE if the file's permissions could be changed. 324 */ 325dbus_bool_t 326_dbus_make_file_world_readable(const DBusString *filename, 327 DBusError *error) 328{ 329 const char *filename_c; 330 331 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 332 333 filename_c = _dbus_string_get_const_data (filename); 334 if (chmod (filename_c, 0644) == -1) 335 { 336 dbus_set_error (error, 337 DBUS_ERROR_FAILED, 338 "Could not change permissions of file %s: %s\n", 339 filename_c, 340 _dbus_strerror (errno)); 341 return FALSE; 342 } 343 return TRUE; 344} 345 346/** Creates the given file, failing if the file already exists. 347 * 348 * @param filename the filename 349 * @param error error location 350 * @returns #TRUE if we created the file and it didn't exist 351 */ 352dbus_bool_t 353_dbus_create_file_exclusively (const DBusString *filename, 354 DBusError *error) 355{ 356 int fd; 357 const char *filename_c; 358 359 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 360 361 filename_c = _dbus_string_get_const_data (filename); 362 363 fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, 364 0600); 365 if (fd < 0) 366 { 367 dbus_set_error (error, 368 DBUS_ERROR_FAILED, 369 "Could not create file %s: %s\n", 370 filename_c, 371 _dbus_strerror (errno)); 372 return FALSE; 373 } 374 375 _dbus_verbose ("exclusive file fd %d opened\n", fd); 376 377 if (!_dbus_close (fd, NULL)) 378 { 379 dbus_set_error (error, 380 DBUS_ERROR_FAILED, 381 "Could not close file %s: %s\n", 382 filename_c, 383 _dbus_strerror (errno)); 384 return FALSE; 385 } 386 387 return TRUE; 388} 389 390/** 391 * Deletes the given file. 392 * 393 * @param filename the filename 394 * @param error error location 395 * 396 * @returns #TRUE if unlink() succeeded 397 */ 398dbus_bool_t 399_dbus_delete_file (const DBusString *filename, 400 DBusError *error) 401{ 402 const char *filename_c; 403 404 _DBUS_ASSERT_ERROR_IS_CLEAR (error); 405 406 filename_c = _dbus_string_get_const_data (filename); 407 408 if (unlink (filename_c) < 0) 409 { 410 dbus_set_error (error, DBUS_ERROR_FAILED, 411 "Failed to delete file %s: %s\n", 412 filename_c, _dbus_strerror (errno)); 413 return FALSE; 414 } 415 else 416 return TRUE; 417} 418