summaryrefslogtreecommitdiffstats
path: root/dbus
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-02-01 04:58:16 +0000
committerHavoc Pennington <hp@redhat.com>2003-02-01 04:58:16 +0000
commite0ffb6eb1472e6766d79346e1fae418c129ef536 (patch)
tree4fddaa6743cfcae6ef5ccac4105d4242d2408773 /dbus
parentd8f9c46bf873fe03dbb1db100f3c6d02b2d6c847 (diff)
2003-02-01 Havoc Pennington <hp@pobox.com>
* dbus/dbus-break-loader.c (main): new program to find messages that break the loader. * dbus/dbus-sysdeps.c (_dbus_string_append_uint): new function * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): new function * dbus/dbus-string.c (_dbus_string_set_byte): new
Diffstat (limited to 'dbus')
-rw-r--r--dbus/Makefile.am11
-rw-r--r--dbus/dbus-break-loader.c539
-rw-r--r--dbus/dbus-marshal.c2
-rw-r--r--dbus/dbus-message.c132
-rw-r--r--dbus/dbus-string.c187
-rw-r--r--dbus/dbus-string.h10
-rw-r--r--dbus/dbus-sysdeps.c91
-rw-r--r--dbus/dbus-sysdeps.h6
-rw-r--r--dbus/dbus-test.h18
9 files changed, 890 insertions, 106 deletions
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
index 98090a62..4ffe7e2c 100644
--- a/dbus/Makefile.am
+++ b/dbus/Makefile.am
@@ -85,12 +85,16 @@ libdbus_1_la_LIBADD= $(DBUS_CLIENT_LIBS) libdbus-convenience.la
## convention for internal symbols)
libdbus_1_la_LDFLAGS= -export-symbols-regex "^[^_].*"
+## FIXME it would be less annoying when hacking if we didn't have
+## to relink these test binaries, so moving them to the test/*
+## subdir would be nice.
+
## note that TESTS has special meaning (stuff to use in make check)
## so if adding tests not to be run in make check, don't add them to
## TESTS
if DBUS_BUILD_TESTS
TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_srcdir)/test/data
-TESTS=dbus-test
+TESTS=dbus-test dbus-break-loader
else
TESTS=
endif
@@ -103,3 +107,8 @@ dbus_test_SOURCES= \
dbus-test-main.c
dbus_test_LDADD= $(DBUS_CLIENT_LIBS) libdbus-convenience.la libdbus-1.la
+
+dbus_break_loader_SOURCES= \
+ dbus-break-loader.c
+
+dbus_break_loader_LDADD= $(DBUS_CLIENT_LIBS) libdbus-convenience.la libdbus-1.la \ No newline at end of file
diff --git a/dbus/dbus-break-loader.c b/dbus/dbus-break-loader.c
new file mode 100644
index 00000000..941b7e59
--- /dev/null
+++ b/dbus/dbus-break-loader.c
@@ -0,0 +1,539 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-break-loader.c Program to find byte streams that break the message loader
+ *
+ * Copyright (C) 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "dbus-types.h"
+#include "dbus-test.h"
+#include "dbus-internals.h"
+#include "dbus-sysdeps.h"
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <string.h>
+
+static DBusString failure_dir;
+static int total_attempts;
+static int failures_this_iteration;
+
+static int
+random_int_in_range (int start,
+ int end)
+{
+ /* such elegant math */
+ double gap;
+ double v_double;
+ int v;
+
+ if (start == end)
+ return start;
+
+ _dbus_assert (end > start);
+
+ gap = end - start - 1; /* -1 to not include "end" */
+ v_double = ((double)start) + (((double)rand ())/RAND_MAX) * gap;
+ if (v_double < 0.0)
+ v = (v_double - 0.5);
+ else
+ v = (v_double + 0.5);
+
+ if (v < start)
+ {
+ fprintf (stderr, "random_int_in_range() generated %d for range [%d,%d)\n",
+ v, start, end);
+ v = start;
+ }
+ else if (v >= end)
+ {
+ fprintf (stderr, "random_int_in_range() generated %d for range [%d,%d)\n",
+ v, start, end);
+ v = end - 1;
+ }
+
+ /* printf (" %d of [%d,%d)\n", v, start, end); */
+
+ return v;
+}
+
+static dbus_bool_t
+try_mutated_data (const DBusString *data)
+{
+ int pid;
+
+ total_attempts += 1;
+ /* printf (" attempt %d\n", total_attempts); */
+
+ pid = fork ();
+
+ if (pid < 0)
+ {
+ fprintf (stderr, "fork() failed: %s\n",
+ strerror (errno));
+ exit (1);
+ return FALSE;
+ }
+
+ if (pid == 0)
+ {
+ /* Child, try loading the data */
+ if (!dbus_internal_do_not_use_try_message_data (data, _DBUS_MESSAGE_UNKNOWN))
+ exit (1);
+ else
+ exit (0);
+ }
+ else
+ {
+ /* Parent, wait for child */
+ int status;
+ DBusString filename;
+ dbus_bool_t failed;
+
+ if (waitpid (pid, &status, 0) < 0)
+ {
+ fprintf (stderr, "waitpid() failed: %s\n", strerror (errno));
+ exit (1);
+ return FALSE;
+ }
+
+ failed = FALSE;
+
+ if (!_dbus_string_init (&filename, _DBUS_INT_MAX) ||
+ !_dbus_string_copy (&failure_dir, 0,
+ &filename, 0) ||
+ !_dbus_string_append_byte (&filename, '/'))
+ {
+ fprintf (stderr, "out of memory\n");
+ exit (1);
+ }
+
+ _dbus_string_append_int (&filename, total_attempts);
+
+ if (WIFEXITED (status))
+ {
+ if (WEXITSTATUS (status) != 0)
+ {
+ _dbus_string_append (&filename, "exited-");
+ _dbus_string_append_int (&filename, WEXITSTATUS (status));
+ failed = TRUE;
+ }
+ }
+ else if (WIFSIGNALED (status))
+ {
+ _dbus_string_append (&filename, "signaled-");
+ _dbus_string_append_int (&filename, WTERMSIG (status));
+ failed = TRUE;
+ }
+
+ if (failed)
+ {
+ const char *filename_c;
+ DBusResultCode result;
+
+ _dbus_string_get_const_data (&filename, &filename_c);
+ printf ("Child failed, writing %s\n",
+ filename_c);
+
+ result = _dbus_string_save_to_file (data, &filename);
+
+ if (result != DBUS_RESULT_SUCCESS)
+ {
+ fprintf (stderr, "Failed to save failed message data: %s\n",
+ dbus_result_to_string (result));
+ exit (1); /* so we can see the seed that was printed out */
+ }
+
+ failures_this_iteration += 1;
+
+ return FALSE;
+ }
+ else
+ return TRUE;
+ }
+
+ _dbus_assert_not_reached ("should not be reached");
+ return TRUE;
+}
+
+static void
+randomly_shorten_or_lengthen (const DBusString *orig_data,
+ DBusString *mutated)
+{
+ int delta;
+
+ if (orig_data != mutated)
+ {
+ _dbus_string_set_length (mutated, 0);
+
+ if (!_dbus_string_copy (orig_data, 0, mutated, 0))
+ _dbus_assert_not_reached ("out of mem");
+ }
+
+ if (_dbus_string_get_length (mutated) == 0)
+ delta = random_int_in_range (0, 10);
+ else
+ delta = random_int_in_range (- _dbus_string_get_length (mutated),
+ _dbus_string_get_length (mutated) * 3);
+
+ if (delta < 0)
+ _dbus_string_shorten (mutated, - delta);
+ else if (delta > 0)
+ {
+ int i = 0;
+
+ i = _dbus_string_get_length (mutated);
+ if (!_dbus_string_lengthen (mutated, delta))
+ _dbus_assert_not_reached ("couldn't lengthen string");
+
+ while (i < _dbus_string_get_length (mutated))
+ {
+ _dbus_string_set_byte (mutated,
+ i,
+ random_int_in_range (0, 256));
+ ++i;
+ }
+ }
+}
+
+static void
+randomly_change_one_byte (const DBusString *orig_data,
+ DBusString *mutated)
+{
+ int i;
+
+ if (orig_data != mutated)
+ {
+ _dbus_string_set_length (mutated, 0);
+
+ if (!_dbus_string_copy (orig_data, 0, mutated, 0))
+ _dbus_assert_not_reached ("out of mem");
+ }
+
+ if (_dbus_string_get_length (mutated) == 0)
+ return;
+
+ i = random_int_in_range (0, _dbus_string_get_length (mutated));
+
+ _dbus_string_set_byte (mutated, i,
+ random_int_in_range (0, 256));
+}
+
+static void
+randomly_remove_one_byte (const DBusString *orig_data,
+ DBusString *mutated)
+{
+ int i;
+
+ if (orig_data != mutated)
+ {
+ _dbus_string_set_length (mutated, 0);
+
+ if (!_dbus_string_copy (orig_data, 0, mutated, 0))
+ _dbus_assert_not_reached ("out of mem");
+ }
+
+ if (_dbus_string_get_length (mutated) == 0)
+ return;
+
+ i = random_int_in_range (0, _dbus_string_get_length (mutated));
+
+ _dbus_string_delete (mutated, i, 1);
+}
+
+
+static void
+randomly_add_one_byte (const DBusString *orig_data,
+ DBusString *mutated)
+{
+ int i;
+
+ if (orig_data != mutated)
+ {
+ _dbus_string_set_length (mutated, 0);
+
+ if (!_dbus_string_copy (orig_data, 0, mutated, 0))
+ _dbus_assert_not_reached ("out of mem");
+ }
+
+ i = random_int_in_range (0, _dbus_string_get_length (mutated));
+
+ _dbus_string_insert_byte (mutated, i,
+ random_int_in_range (0, 256));
+}
+
+static void
+randomly_do_n_things (const DBusString *orig_data,
+ DBusString *mutated,
+ int n)
+{
+ int i;
+ void (* functions[]) (const DBusString *orig_data,
+ DBusString *mutated) =
+ {
+ randomly_shorten_or_lengthen,
+ randomly_change_one_byte,
+ randomly_add_one_byte,
+ randomly_remove_one_byte
+ };
+
+ _dbus_string_set_length (mutated, 0);
+
+ if (!_dbus_string_copy (orig_data, 0, mutated, 0))
+ _dbus_assert_not_reached ("out of mem");
+
+ i = 0;
+ while (i < n)
+ {
+ int which;
+
+ which = random_int_in_range (0, _DBUS_N_ELEMENTS (functions));
+
+ (* functions[which]) (mutated, mutated);
+
+ ++i;
+ }
+}
+
+static dbus_bool_t
+find_breaks_based_on (const DBusString *filename,
+ dbus_bool_t is_raw,
+ DBusMessageValidity expected_validity,
+ void *data)
+{
+ DBusString orig_data;
+ DBusString mutated;
+ const char *filename_c;
+ dbus_bool_t retval;
+ int i;
+
+ _dbus_string_get_const_data (filename, &filename_c);
+
+ retval = FALSE;
+
+ if (!_dbus_string_init (&orig_data, _DBUS_INT_MAX))
+ _dbus_assert_not_reached ("could not allocate string\n");
+
+ if (!_dbus_string_init (&mutated, _DBUS_INT_MAX))
+ _dbus_assert_not_reached ("could not allocate string\n");
+
+ if (!dbus_internal_do_not_use_load_message_file (filename, is_raw,
+ &orig_data))
+ {
+ fprintf (stderr, "could not load file %s\n", filename_c);
+ goto failed;
+ }
+
+ i = 0;
+ while (i < 100)
+ {
+ randomly_change_one_byte (&orig_data, &mutated);
+ try_mutated_data (&mutated);
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < 50)
+ {
+ randomly_remove_one_byte (&orig_data, &mutated);
+ try_mutated_data (&mutated);
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < 50)
+ {
+ randomly_add_one_byte (&orig_data, &mutated);
+ try_mutated_data (&mutated);
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < 15)
+ {
+ randomly_shorten_or_lengthen (&orig_data, &mutated);
+ try_mutated_data (&mutated);
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < 42)
+ {
+ randomly_do_n_things (&orig_data, &mutated, 2);
+ try_mutated_data (&mutated);
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < 42)
+ {
+ randomly_do_n_things (&orig_data, &mutated, 3);
+ try_mutated_data (&mutated);
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < 42)
+ {
+ randomly_do_n_things (&orig_data, &mutated, 4);
+ try_mutated_data (&mutated);
+
+ ++i;
+ }
+
+ retval = TRUE;
+
+ failed:
+
+ _dbus_string_free (&orig_data);
+ _dbus_string_free (&mutated);
+
+ /* FALSE means end the whole process */
+ return retval;
+}
+
+static unsigned int
+get_random_seed (void)
+{
+ DBusString bytes;
+ unsigned int seed;
+ int fd;
+ const char *s;
+
+ seed = 0;
+
+ if (!_dbus_string_init (&bytes, _DBUS_INT_MAX))
+ exit (1);
+
+ fd = open ("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ goto use_fallback;
+
+ if (_dbus_read (fd, &bytes, 4) != 4)
+ goto use_fallback;
+
+ close (fd);
+
+ _dbus_string_get_const_data (&bytes, &s);
+
+ seed = * (unsigned int*) s;
+ goto out;
+
+ use_fallback:
+ {
+ long tv_usec;
+
+ fprintf (stderr, "could not open/read /dev/urandom, using current time for seed\n");
+
+ _dbus_get_current_time (NULL, &tv_usec);
+
+ seed = tv_usec;
+ }
+
+ out:
+ _dbus_string_free (&bytes);
+
+ return seed;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ const char *test_data_dir;
+ const char *failure_dir_c;
+ int total_failures_found;
+
+ if (argc > 1)
+ test_data_dir = argv[1];
+ else
+ {
+ fprintf (stderr, "Must specify a top_srcdir/test/data directory\n");
+ return 1;
+ }
+
+ total_failures_found = 0;
+ total_attempts = 0;
+
+ if (!_dbus_string_init (&failure_dir, _DBUS_INT_MAX))
+ return 1;
+
+ /* so you can leave it overnight safely */
+#define MAX_FAILURES 1000
+
+ while (total_failures_found < MAX_FAILURES)
+ {
+ unsigned int seed;
+
+ failures_this_iteration = 0;
+
+ seed = get_random_seed ();
+
+ _dbus_string_set_length (&failure_dir, 0);
+
+ if (!_dbus_string_append (&failure_dir, "failures-"))
+ return 1;
+
+ if (!_dbus_string_append_uint (&failure_dir, seed))
+ return 1;
+
+ _dbus_string_get_const_data (&failure_dir, &failure_dir_c);
+
+ if (mkdir (failure_dir_c, 0700) < 0)
+ {
+ if (errno != EEXIST)
+ fprintf (stderr, "didn't mkdir %s: %s\n",
+ failure_dir_c, strerror (errno));
+ }
+
+ printf ("next seed = %u \ttotal failures %d of %d attempts\n",
+ seed, total_failures_found, total_attempts);
+
+ srand (seed);
+
+ if (!dbus_internal_do_not_use_foreach_message_file (test_data_dir,
+ find_breaks_based_on,
+ NULL))
+ {
+ fprintf (stderr, "fatal error iterating over message files\n");
+ rmdir (failure_dir_c);
+ return 1;
+ }
+
+ printf ("Found %d failures with seed %u stored in %s\n",
+ failures_this_iteration, seed, failure_dir_c);
+
+ total_failures_found += failures_this_iteration;
+
+ rmdir (failure_dir_c); /* does nothing if non-empty */
+ }
+
+ return 0;
+}
diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c
index 2a674987..37128a28 100644
--- a/dbus/dbus-marshal.c
+++ b/dbus/dbus-marshal.c
@@ -1225,7 +1225,7 @@ _dbus_marshal_validate_arg (const DBusString *str,
break;
default:
- _dbus_warn ("Unknown message arg type %d\n", *data);
+ _dbus_verbose ("Unknown message arg type %d\n", *data);
return FALSE;
}
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index 7b116607..c4eca849 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -2483,39 +2483,27 @@ check_loader_results (DBusMessageLoader *loader,
/**
- * Tries loading the message in the given message file.
- * The file must end in .message for our message-builder language
- * or .message-raw for a binary file to be treated as a message
- * verbatim.
- *
+ * Loads the message in the given message file.
*
* @param filename filename to load
* @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
- * @param expected_validity what the message has to be like to return #TRUE
- * @returns #TRUE if the message has the expected validity
+ * @param data string to load message into
+ * @returns #TRUE if the message was loaded
*/
dbus_bool_t
-dbus_internal_do_not_use_try_message_file (const DBusString *filename,
- dbus_bool_t is_raw,
- DBusMessageValidity expected_validity)
+dbus_internal_do_not_use_load_message_file (const DBusString *filename,
+ dbus_bool_t is_raw,
+ DBusString *data)
{
- DBusString data;
- DBusMessageLoader *loader;
dbus_bool_t retval;
- int len;
- int i;
- loader = NULL;
- retval = FALSE;
-
- if (!_dbus_string_init (&data, _DBUS_INT_MAX))
- _dbus_assert_not_reached ("could not allocate string\n");
+ retval = FALSE;
if (is_raw)
{
DBusResultCode result;
- result = _dbus_file_get_contents (&data, filename);
+ result = _dbus_file_get_contents (data, filename);
if (result != DBUS_RESULT_SUCCESS)
{
const char *s;
@@ -2526,7 +2514,7 @@ dbus_internal_do_not_use_try_message_file (const DBusString *filename,
}
else
{
- if (!_dbus_message_data_load (&data, filename))
+ if (!_dbus_message_data_load (data, filename))
{
const char *s;
_dbus_string_get_const_data (filename, &s);
@@ -2535,18 +2523,93 @@ dbus_internal_do_not_use_try_message_file (const DBusString *filename,
}
}
+ retval = TRUE;
+
+ failed:
+
+ return retval;
+}
+
+/**
+ * Tries loading the message in the given message file
+ * and verifies that DBusMessageLoader can handle it.
+ *
+ * @param filename filename to load
+ * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
+ * @param expected_validity what the message has to be like to return #TRUE
+ * @returns #TRUE if the message has the expected validity
+ */
+dbus_bool_t
+dbus_internal_do_not_use_try_message_file (const DBusString *filename,
+ dbus_bool_t is_raw,
+ DBusMessageValidity expected_validity)
+{
+ DBusString data;
+ dbus_bool_t retval;
+
+ retval = FALSE;
+
+ if (!_dbus_string_init (&data, _DBUS_INT_MAX))
+ _dbus_assert_not_reached ("could not allocate string\n");
+
+ if (!dbus_internal_do_not_use_load_message_file (filename, is_raw,
+ &data))
+ goto failed;
+
+ retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity);
+
+ failed:
+
+ if (!retval)
+ {
+ const char *s;
+
+ if (_dbus_string_get_length (&data) > 0)
+ _dbus_verbose_bytes_of_string (&data, 0,
+ _dbus_string_get_length (&data));
+
+ _dbus_string_get_const_data (filename, &s);
+ _dbus_warn ("Failed message loader test on %s\n",
+ s);
+ }
+
+ _dbus_string_free (&data);
+
+ return retval;
+}
+
+/**
+ * Tries loading the given message data.
+ *
+ *
+ * @param data the message data
+ * @param expected_validity what the message has to be like to return #TRUE
+ * @returns #TRUE if the message has the expected validity
+ */
+dbus_bool_t
+dbus_internal_do_not_use_try_message_data (const DBusString *data,
+ DBusMessageValidity expected_validity)
+{
+ DBusMessageLoader *loader;
+ dbus_bool_t retval;
+ int len;
+ int i;
+
+ loader = NULL;
+ retval = FALSE;
+
/* Write the data one byte at a time */
loader = _dbus_message_loader_new ();
- len = _dbus_string_get_length (&data);
+ len = _dbus_string_get_length (data);
for (i = 0; i < len; i++)
{
DBusString *buffer;
_dbus_message_loader_get_buffer (loader, &buffer);
_dbus_string_append_byte (buffer,
- _dbus_string_get_byte (&data, i));
+ _dbus_string_get_byte (data, i));
_dbus_message_loader_return_buffer (loader, buffer, 1);
}
@@ -2564,7 +2627,7 @@ dbus_internal_do_not_use_try_message_file (const DBusString *filename,
DBusString *buffer;
_dbus_message_loader_get_buffer (loader, &buffer);
- _dbus_string_copy (&data, 0, buffer,
+ _dbus_string_copy (data, 0, buffer,
_dbus_string_get_length (buffer));
_dbus_message_loader_return_buffer (loader, buffer, 1);
}
@@ -2579,17 +2642,17 @@ dbus_internal_do_not_use_try_message_file (const DBusString *filename,
loader = _dbus_message_loader_new ();
- len = _dbus_string_get_length (&data);
+ len = _dbus_string_get_length (data);
for (i = 0; i < len; i += 2)
{
DBusString *buffer;
_dbus_message_loader_get_buffer (loader, &buffer);
_dbus_string_append_byte (buffer,
- _dbus_string_get_byte (&data, i));
+ _dbus_string_get_byte (data, i));
if ((i+1) < len)
_dbus_string_append_byte (buffer,
- _dbus_string_get_byte (&data, i+1));
+ _dbus_string_get_byte (data, i+1));
_dbus_message_loader_return_buffer (loader, buffer, 1);
}
@@ -2602,22 +2665,9 @@ dbus_internal_do_not_use_try_message_file (const DBusString *filename,
retval = TRUE;
failed:
- if (!retval)
- {
- const char *s;
-
- if (_dbus_string_get_length (&data) > 0)
- _dbus_verbose_bytes_of_string (&data, 0,
- _dbus_string_get_length (&data));
-
- _dbus_string_get_const_data (filename, &s);
- _dbus_warn ("Failed message loader test on %s\n",
- s);
- }
if (loader)
_dbus_message_loader_unref (loader);
- _dbus_string_free (&data);
return retval;
}
@@ -2648,7 +2698,7 @@ process_test_subdir (const DBusString *test_base_dir,
_dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
if (!_dbus_concat_dir_and_file (&test_directory, &filename))
- _dbus_assert_not_reached ("could't allocate full path");
+ _dbus_assert_not_reached ("couldn't allocate full path");
_dbus_string_free (&filename);
if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
index 05d14ba1..17a7d918 100644
--- a/dbus/dbus-string.c
+++ b/dbus/dbus-string.c
@@ -299,6 +299,59 @@ _dbus_string_lock (DBusString *str)
}
}
+static dbus_bool_t
+set_length (DBusRealString *real,
+ int new_length)
+{
+ /* Note, we are setting the length without nul termination */
+
+ /* exceeding max length is the same as failure to allocate memory */
+ if (new_length > real->max_length)
+ return FALSE;
+
+ while (new_length >= real->allocated)
+ {
+ int new_allocated;
+ char *new_str;
+
+ new_allocated = 2 + real->allocated * 2;
+ if (new_allocated < real->allocated)
+ return FALSE; /* overflow */
+
+ new_str = dbus_realloc (real->str, new_allocated);
+ if (new_str == NULL)
+ return FALSE;
+
+ real->str = new_str;
+ real->allocated = new_allocated;
+
+ ASSERT_8_BYTE_ALIGNED (real);
+ }
+
+ real->len = new_length;
+ real->str[real->len] = '\0';
+
+ return TRUE;
+}
+
+static dbus_bool_t
+open_gap (int len,
+ DBusRealString *dest,
+ int insert_at)
+{
+ if (len == 0)
+ return TRUE;
+
+ if (!set_length (dest, dest->len + len))
+ return FALSE;
+
+ memmove (dest->str + insert_at + len,
+ dest->str + insert_at,
+ dest->len - len - insert_at);
+
+ return TRUE;
+}
+
/**
* Gets the raw character buffer from the string. The returned buffer
* will be nul-terminated, but note that strings may contain binary
@@ -388,13 +441,31 @@ _dbus_string_get_const_data_len (const DBusString *str,
}
/**
+ * Sets the value of the byte at the given position.
+ *
+ * @param str the string
+ * @param i the position
+ * @param byte the new value
+ */
+void
+_dbus_string_set_byte (DBusString *str,
+ int i,
+ unsigned char byte)
+{
+ DBUS_STRING_PREAMBLE (str);
+ _dbus_assert (i < real->len);
+
+ real->str[i] = byte;
+}
+
+/**
* Gets the byte at the given position.
*
* @param str the string
* @param start the position
* @returns the byte at that position
*/
-char
+unsigned char
_dbus_string_get_byte (const DBusString *str,
int start)
{
@@ -405,6 +476,30 @@ _dbus_string_get_byte (const DBusString *str,
}
/**
+ * Inserts the given byte at the given position.
+ *
+ * @param str the string
+ * @param i the position
+ * @param byte the value to insert
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_string_insert_byte (DBusString *str,
+ int i,
+ unsigned char byte)
+{
+ DBUS_STRING_PREAMBLE (str);
+ _dbus_assert (i <= real->len);
+
+ if (!open_gap (1, real, i))
+ return FALSE;
+
+ real->str[i] = byte;
+
+ return TRUE;
+}
+
+/**
* Like _dbus_string_get_data(), but removes the
* gotten data from the original string. The caller
* must free the data returned. This function may
@@ -493,41 +588,6 @@ _dbus_string_get_length (const DBusString *str)
return real->len;
}
-static dbus_bool_t
-set_length (DBusRealString *real,
- int new_length)
-{
- /* Note, we are setting the length without nul termination */
-
- /* exceeding max length is the same as failure to allocate memory */
- if (new_length > real->max_length)
- return FALSE;
-
- while (new_length >= real->allocated)
- {
- int new_allocated;
- char *new_str;
-
- new_allocated = 2 + real->allocated * 2;
- if (new_allocated < real->allocated)
- return FALSE; /* overflow */
-
- new_str = dbus_realloc (real->str, new_allocated);
- if (new_str == NULL)
- return FALSE;
-
- real->str = new_str;
- real->allocated = new_allocated;
-
- ASSERT_8_BYTE_ALIGNED (real);
- }
-
- real->len = new_length;
- real->str[real->len] = '\0';
-
- return TRUE;
-}
-
/**
* Makes a string longer by the given number of bytes. Checks whether
* adding additional_length to the current length would overflow an
@@ -812,24 +872,6 @@ _dbus_string_delete (DBusString *str,
}
static dbus_bool_t
-open_gap (int len,
- DBusRealString *dest,
- int insert_at)
-{
- if (len == 0)
- return TRUE;
-
- if (!set_length (dest, dest->len + len))
- return FALSE;
-
- memmove (dest->str + insert_at + len,
- dest->str + insert_at,
- dest->len - len - insert_at);
-
- return TRUE;
-}
-
-static dbus_bool_t
copy (DBusRealString *source,
int start,
int len,
@@ -2282,6 +2324,43 @@ _dbus_string_test (void)
_dbus_assert (i == _dbus_string_get_length (&str));
_dbus_string_free (&str);
+
+ /* Check insert/set/get byte */
+
+ if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+ _dbus_assert_not_reached ("failed to init string");
+
+ if (!_dbus_string_append (&str, "Hello"))
+ _dbus_assert_not_reached ("failed to append Hello");
+
+ _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H');
+ _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e');
+ _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l');
+ _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l');
+ _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o');
+
+ _dbus_string_set_byte (&str, 1, 'q');
+ _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
+
+ if (!_dbus_string_insert_byte (&str, 0, 255))
+ _dbus_assert_not_reached ("can't insert byte");
+
+ if (!_dbus_string_insert_byte (&str, 2, 'Z'))
+ _dbus_assert_not_reached ("can't insert byte");
+
+ if (!_dbus_string_insert_byte (&str, _dbus_string_get_length (&str), 'W'))
+ _dbus_assert_not_reached ("can't insert byte");
+
+ _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
+ _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
+ _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
+ _dbus_assert (_dbus_string_get_byte (&str, 3) == 'q');
+ _dbus_assert (_dbus_string_get_byte (&str, 4) == 'l');
+ _dbus_assert (_dbus_string_get_byte (&str, 5) == 'l');
+ _dbus_assert (_dbus_string_get_byte (&str, 6) == 'o');
+ _dbus_assert (_dbus_string_get_byte (&str, 7) == 'W');
+
+ _dbus_string_free (&str);
/* Check append/parse int/double */
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
index 641eaf5e..54297ee7 100644
--- a/dbus/dbus-string.h
+++ b/dbus/dbus-string.h
@@ -66,8 +66,14 @@ void _dbus_string_get_const_data_len (const DBusString *str,
const char **data_return,
int start,
int len);
-char _dbus_string_get_byte (const DBusString *str,
+void _dbus_string_set_byte (DBusString *str,
+ int i,
+ unsigned char byte);
+unsigned char _dbus_string_get_byte (const DBusString *str,
int start);
+dbus_bool_t _dbus_string_insert_byte (DBusString *str,
+ int i,
+ unsigned char byte);
dbus_bool_t _dbus_string_steal_data (DBusString *str,
char **data_return);
dbus_bool_t _dbus_string_steal_data_len (DBusString *str,
@@ -93,6 +99,8 @@ dbus_bool_t _dbus_string_append_len (DBusString *str,
int len);
dbus_bool_t _dbus_string_append_int (DBusString *str,
long value);
+dbus_bool_t _dbus_string_append_uint (DBusString *str,
+ unsigned long value);
dbus_bool_t _dbus_string_append_double (DBusString *str,
double value);
dbus_bool_t _dbus_string_append_byte (DBusString *str,
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index bcb81f7d..17445a8f 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -618,6 +618,44 @@ _dbus_string_append_int (DBusString *str,
}
/**
+ * Appends an unsigned integer to a DBusString.
+ *
+ * @param str the string
+ * @param value the integer value
+ * @returns #FALSE if not enough memory or other failure.
+ */
+dbus_bool_t
+_dbus_string_append_uint (DBusString *str,
+ unsigned long value)
+{
+ /* this is wrong, but definitely on the high side. */
+#define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
+ int orig_len;
+ int i;
+ char *buf;
+
+ orig_len = _dbus_string_get_length (str);
+
+ if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
+ return FALSE;
+
+ _dbus_string_get_data_len (str, &buf, orig_len, MAX_ULONG_LEN);
+
+ snprintf (buf, MAX_ULONG_LEN, "%lu", value);
+
+ i = 0;
+ while (*buf)
+ {
+ ++buf;
+ ++i;
+ }
+
+ _dbus_string_shorten (str, MAX_ULONG_LEN - i);
+
+ return TRUE;
+}
+
+/**
* Appends a double to a DBusString.
*
* @param str the string
@@ -1103,6 +1141,59 @@ _dbus_file_get_contents (DBusString *str,
}
/**
+ * Writes a string out to a file.
+ *
+ * @param str the string to write out
+ * @param filename the file to save string to
+ * @returns result code
+ */
+DBusResultCode
+_dbus_string_save_to_file (const DBusString *str,
+ const DBusString *filename)
+{
+ int fd;
+ int bytes_to_write;
+ const char *filename_c;
+ int total;
+
+ _dbus_string_get_const_data (filename, &filename_c);
+
+ fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
+ 0700);
+ if (fd < 0)
+ return _dbus_result_from_errno (errno);
+
+ total = 0;
+ bytes_to_write = _dbus_string_get_length (str);
+
+ while (total < bytes_to_write)
+ {
+ int bytes_written;
+
+ bytes_written = _dbus_write (fd, str, total,
+ bytes_to_write - total);
+
+ if (bytes_written <= 0)
+ {
+ DBusResultCode result;
+
+ result = _dbus_result_from_errno (errno); /* prior to close() */
+
+ _dbus_verbose ("write() failed: %s",
+ _dbus_strerror (errno));
+
+ close (fd);
+ return result;
+ }
+
+ total += bytes_written;
+ }
+
+ close (fd);
+ return DBUS_RESULT_SUCCESS;
+}
+
+/**
* Appends the given filename to the given directory.
*
* @param dir the directory name
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index fc552e7f..fd0d93de 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -122,8 +122,10 @@ void _dbus_sleep_milliseconds (int milliseconds);
void _dbus_get_current_time (long *tv_sec,
long *tv_usec);
-DBusResultCode _dbus_file_get_contents (DBusString *str,
- const DBusString *filename);
+DBusResultCode _dbus_file_get_contents (DBusString *str,
+ const DBusString *filename);
+DBusResultCode _dbus_string_save_to_file (const DBusString *str,
+ const DBusString *filename);
dbus_bool_t _dbus_concat_dir_and_file (DBusString *dir,
const DBusString *next_component);
diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h
index 28a84447..31753ac0 100644
--- a/dbus/dbus-test.h
+++ b/dbus/dbus-test.h
@@ -43,10 +43,16 @@ dbus_bool_t _dbus_string_test (void);
dbus_bool_t _dbus_address_test (void);
dbus_bool_t _dbus_message_test (const char *test_data_dir);
-void dbus_internal_do_not_use_run_tests (const char *test_data_dir);
-dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename,
- dbus_bool_t is_raw,
- DBusMessageValidity expected_validity);
+void dbus_internal_do_not_use_run_tests (const char *test_data_dir);
+dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename,
+ dbus_bool_t is_raw,
+ DBusMessageValidity expected_validity);
+dbus_bool_t dbus_internal_do_not_use_try_message_data (const DBusString *data,
+ DBusMessageValidity expected_validity);
+dbus_bool_t dbus_internal_do_not_use_load_message_file (const DBusString *filename,
+ dbus_bool_t is_raw,
+ DBusString *data);
+
/* returns FALSE on fatal failure */
typedef dbus_bool_t (* DBusForeachMessageFileFunc) (const DBusString *filename,
@@ -55,8 +61,8 @@ typedef dbus_bool_t (* DBusForeachMessageFileFunc) (const DBusString *filename
void *data);
dbus_bool_t dbus_internal_do_not_use_foreach_message_file (const char *test_data_dir,
- DBusForeachMessageFileFunc func,
- void *user_data);
+ DBusForeachMessageFileFunc func,
+ void *user_data);