summaryrefslogtreecommitdiffstats
path: root/dbus/dbus-sysdeps.c
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-02-24 02:24:13 +0000
committerHavoc Pennington <hp@redhat.com>2003-02-24 02:24:13 +0000
commit2f38c959212d98e2194139daa9120fda37415b4f (patch)
tree725edc511caad936a6ab424d451533c9ce3ff48e /dbus/dbus-sysdeps.c
parent32b4b2a2f6b4dc7b2ee07f1efb75ec8c871ca04b (diff)
2003-02-23 Havoc Pennington <hp@pobox.com>
* dbus/dbus-keyring.c: finish most of this implementation and simple unit test * dbus/dbus-errors.c (dbus_set_error_const, dbus_set_error): make these barf if the error isn't cleared to NULL * dbus/dbus-sysdeps.c (_dbus_delete_file): set error on failure (_dbus_create_directory): new function * dbus/dbus-errors.c (dbus_set_error): fix warning * dbus/dbus-string.c (_dbus_string_hex_encode): new function (_dbus_string_hex_decode): new function (test_hex_roundtrip): test code * dbus/dbus-sha.c (_dbus_sha_compute): use dbus_string_hex_encode * dbus/dbus-md5.c (_dbus_md5_compute): use dbus_string_hex_encode * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): make this use the save-to-temp/rename trick to atomically write the new file (_dbus_string_parse_uint): new function
Diffstat (limited to 'dbus/dbus-sysdeps.c')
-rw-r--r--dbus/dbus-sysdeps.c208
1 files changed, 198 insertions, 10 deletions
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index 8c0567ed..4d610a4d 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -931,6 +931,45 @@ _dbus_string_parse_int (const DBusString *str,
}
/**
+ * Parses an unsigned integer contained in a DBusString. Either return
+ * parameter may be #NULL if you aren't interested in it. The integer
+ * is parsed and stored in value_return. Return parameters are not
+ * initialized if the function returns #FALSE.
+ *
+ * @param str the string
+ * @param start the byte index of the start of the integer
+ * @param value_return return location of the integer value or #NULL
+ * @param end_return return location of the end of the integer, or #NULL
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_string_parse_uint (const DBusString *str,
+ int start,
+ unsigned long *value_return,
+ int *end_return)
+{
+ unsigned long v;
+ const char *p;
+ char *end;
+
+ _dbus_string_get_const_data_len (str, &p, start,
+ _dbus_string_get_length (str) - start);
+
+ end = NULL;
+ errno = 0;
+ v = strtoul (p, &end, 0);
+ if (end == NULL || end == p || errno != 0)
+ return FALSE;
+
+ if (value_return)
+ *value_return = v;
+ if (end_return)
+ *end_return = start + (end - p);
+
+ return TRUE;
+}
+
+/**
* Parses a floating point number contained in a DBusString. Either
* return parameter may be #NULL if you aren't interested in it. The
* integer is parsed and stored in value_return. Return parameters are
@@ -1623,8 +1662,39 @@ _dbus_file_get_contents (DBusString *str,
}
}
+static dbus_bool_t
+append_unique_chars (DBusString *str)
+{
+ static const char letters[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ int i;
+ int len;
+
+#define N_UNIQUE_CHARS 8
+
+ if (!_dbus_generate_random_bytes (str, N_UNIQUE_CHARS))
+ return FALSE;
+
+ len = _dbus_string_get_length (str);
+ i = len - N_UNIQUE_CHARS;
+ while (i < len)
+ {
+ _dbus_string_set_byte (str, i,
+ letters[_dbus_string_get_byte (str, i) %
+ (sizeof (letters) - 1)]);
+
+ ++i;
+ }
+
+ _dbus_assert (_dbus_string_validate_ascii (str, len - N_UNIQUE_CHARS,
+ N_UNIQUE_CHARS));
+
+ return TRUE;
+}
+
/**
- * Writes a string out to a file.
+ * Writes a string out to a file. If the file exists,
+ * it will be atomically overwritten by the new data.
*
* @param str the string to write out
* @param filename the file to save string to
@@ -1637,15 +1707,41 @@ _dbus_string_save_to_file (const DBusString *str,
int fd;
int bytes_to_write;
const char *filename_c;
+ DBusString tmp_filename;
+ const char *tmp_filename_c;
int total;
+ DBusResultCode result;
+ dbus_bool_t need_unlink;
+
+ fd = -1;
+ result = DBUS_RESULT_FAILED;
+ need_unlink = FALSE;
+
+ if (!_dbus_string_init (&tmp_filename, _DBUS_INT_MAX))
+ return DBUS_RESULT_NO_MEMORY;
- _dbus_string_get_const_data (filename, &filename_c);
+ if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
+ return DBUS_RESULT_NO_MEMORY;
- fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
+ if (!_dbus_string_append (&tmp_filename, "."))
+ return DBUS_RESULT_NO_MEMORY;
+
+ if (!append_unique_chars (&tmp_filename))
+ return DBUS_RESULT_NO_MEMORY;
+
+ _dbus_string_get_const_data (filename, &filename_c);
+ _dbus_string_get_const_data (&tmp_filename, &tmp_filename_c);
+
+ fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
0600);
if (fd < 0)
- return _dbus_result_from_errno (errno);
+ {
+ result = _dbus_result_from_errno (errno);
+ goto out;
+ }
+ need_unlink = TRUE;
+
total = 0;
bytes_to_write = _dbus_string_get_length (str);
@@ -1665,15 +1761,45 @@ _dbus_string_save_to_file (const DBusString *str,
_dbus_verbose ("write() failed: %s",
_dbus_strerror (errno));
- close (fd);
- return result;
+ goto out;
}
total += bytes_written;
}
- close (fd);
- return DBUS_RESULT_SUCCESS;
+ if (close (fd) < 0)
+ {
+ _dbus_verbose ("close() failed: %s\n", _dbus_strerror (errno));
+ goto out;
+ }
+
+ fd = -1;
+
+ if (rename (tmp_filename_c, filename_c) < 0)
+ {
+ _dbus_verbose ("rename() failed: %s\n", _dbus_strerror (errno));
+ goto out;
+ }
+
+ need_unlink = FALSE;
+
+ result = DBUS_RESULT_SUCCESS;
+
+ out:
+ /* close first, then unlink, to prevent ".nfs34234235" garbage
+ * files
+ */
+
+ if (fd >= 0)
+ close (fd);
+
+ if (need_unlink && unlink (tmp_filename_c) < 0)
+ _dbus_verbose ("Failed to unlink temp file %s: %s\n",
+ tmp_filename_c, _dbus_strerror (errno));
+
+ _dbus_string_free (&tmp_filename);
+
+ return result;
}
/** Creates the given file, failing if the file already exists.
@@ -1733,7 +1859,42 @@ _dbus_delete_file (const DBusString *filename,
_dbus_string_get_const_data (filename, &filename_c);
if (unlink (filename_c) < 0)
- return FALSE;
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Failed to delete file %s: %s\n",
+ filename_c, _dbus_strerror (errno));
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+/**
+ * Creates a directory; succeeds if the directory
+ * is created or already existed.
+ *
+ * @param filename directory filename
+ * @param error initialized error object
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_create_directory (const DBusString *filename,
+ DBusError *error)
+{
+ const char *filename_c;
+
+ _dbus_string_get_const_data (filename, &filename_c);
+
+ if (mkdir (filename_c, 0700) < 0)
+ {
+ if (errno == EEXIST)
+ return TRUE;
+
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Failed to create directory %s: %s\n",
+ filename_c, _dbus_strerror (errno));
+ return FALSE;
+ }
else
return TRUE;
}
@@ -1907,6 +2068,8 @@ _dbus_generate_random_bytes (DBusString *str,
int i;
/* fall back to pseudorandom */
+ _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
+ n_bytes);
_dbus_get_current_time (NULL, &tv_usec);
srand (tv_usec);
@@ -1915,7 +2078,7 @@ _dbus_generate_random_bytes (DBusString *str,
while (i < n_bytes)
{
double r;
- int b;
+ unsigned int b;
r = rand ();
b = (r / (double) RAND_MAX) * 255.0;
@@ -1933,6 +2096,9 @@ _dbus_generate_random_bytes (DBusString *str,
if (_dbus_read (fd, str, n_bytes) != n_bytes)
goto failed;
+ _dbus_verbose ("Read %d bytes from /dev/urandom\n",
+ n_bytes);
+
close (fd);
return TRUE;
@@ -1948,6 +2114,9 @@ _dbus_generate_random_bytes (DBusString *str,
/**
* A wrapper around strerror()
*
+ * @todo get rid of this function, it's the same as
+ * _dbus_strerror().
+ *
* @param errnum the errno
* @returns an error message (never #NULL)
*/
@@ -1963,6 +2132,25 @@ _dbus_errno_to_string (int errnum)
return msg;
}
+/**
+ * A wrapper around strerror() because some platforms
+ * may be lame and not have strerror().
+ *
+ * @param error_number errno.
+ * @returns error description.
+ */
+const char*
+_dbus_strerror (int error_number)
+{
+ const char *msg;
+
+ msg = strerror (error_number);
+ if (msg == NULL)
+ msg = "unknown";
+
+ return msg;
+}
+
/* Avoids a danger in threaded situations (calling close()
* on a file descriptor twice, and another thread has
* re-opened it since the first close)