diff options
author | Havoc Pennington <hp@redhat.com> | 2003-02-01 04:58:16 +0000 |
---|---|---|
committer | Havoc Pennington <hp@redhat.com> | 2003-02-01 04:58:16 +0000 |
commit | e0ffb6eb1472e6766d79346e1fae418c129ef536 (patch) | |
tree | 4fddaa6743cfcae6ef5ccac4105d4242d2408773 /dbus | |
parent | d8f9c46bf873fe03dbb1db100f3c6d02b2d6c847 (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.am | 11 | ||||
-rw-r--r-- | dbus/dbus-break-loader.c | 539 | ||||
-rw-r--r-- | dbus/dbus-marshal.c | 2 | ||||
-rw-r--r-- | dbus/dbus-message.c | 132 | ||||
-rw-r--r-- | dbus/dbus-string.c | 187 | ||||
-rw-r--r-- | dbus/dbus-string.h | 10 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.c | 91 | ||||
-rw-r--r-- | dbus/dbus-sysdeps.h | 6 | ||||
-rw-r--r-- | dbus/dbus-test.h | 18 |
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); |