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
This commit is contained in:
Havoc Pennington 2003-02-01 04:58:16 +00:00
parent d8f9c46bf8
commit e0ffb6eb14
10 changed files with 910 additions and 116 deletions

View file

@ -1,3 +1,13 @@
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
2003-01-31 Havoc Pennington <hp@pobox.com>
* dbus/dbus-message.c: refactor the test code to be more general,

View file

@ -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

539
dbus/dbus-break-loader.c Normal file
View file

@ -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;
}

View file

@ -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;
}

View file

@ -2483,11 +2483,56 @@ 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 data string to load message into
* @returns #TRUE if the message was loaded
*/
dbus_bool_t
dbus_internal_do_not_use_load_message_file (const DBusString *filename,
dbus_bool_t is_raw,
DBusString *data)
{
dbus_bool_t retval;
retval = FALSE;
if (is_raw)
{
DBusResultCode result;
result = _dbus_file_get_contents (data, filename);
if (result != DBUS_RESULT_SUCCESS)
{
const char *s;
_dbus_string_get_const_data (filename, &s);
_dbus_warn ("Could not load message file %s\n", s);
goto failed;
}
}
else
{
if (!_dbus_message_data_load (data, filename))
{
const char *s;
_dbus_string_get_const_data (filename, &s);
_dbus_warn ("Could not load message file %s\n", s);
goto failed;
}
}
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
@ -2500,6 +2545,51 @@ dbus_internal_do_not_use_try_message_file (const DBusString *filename,
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;
@ -2507,46 +2597,19 @@ dbus_internal_do_not_use_try_message_file (const DBusString *filename,
loader = NULL;
retval = FALSE;
if (!_dbus_string_init (&data, _DBUS_INT_MAX))
_dbus_assert_not_reached ("could not allocate string\n");
if (is_raw)
{
DBusResultCode result;
result = _dbus_file_get_contents (&data, filename);
if (result != DBUS_RESULT_SUCCESS)
{
const char *s;
_dbus_string_get_const_data (filename, &s);
_dbus_warn ("Could not load message file %s\n", s);
goto failed;
}
}
else
{
if (!_dbus_message_data_load (&data, filename))
{
const char *s;
_dbus_string_get_const_data (filename, &s);
_dbus_warn ("Could not load message file %s\n", s);
goto failed;
}
}
/* 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))

View file

@ -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
@ -387,6 +440,24 @@ _dbus_string_get_const_data_len (const DBusString *str,
*data_return = real->str + start;
}
/**
* 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.
*
@ -394,7 +465,7 @@ _dbus_string_get_const_data_len (const DBusString *str,
* @param start the position
* @returns the byte at that position
*/
char
unsigned char
_dbus_string_get_byte (const DBusString *str,
int start)
{
@ -404,6 +475,30 @@ _dbus_string_get_byte (const DBusString *str,
return real->str[start];
}
/**
* 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
@ -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
@ -811,24 +871,6 @@ _dbus_string_delete (DBusString *str,
delete (real, start, len);
}
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,
@ -2281,6 +2323,43 @@ _dbus_string_test (void)
_dbus_assert (ch == 0xfffc);
_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 */

View file

@ -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,

View file

@ -617,6 +617,44 @@ _dbus_string_append_int (DBusString *str,
return TRUE;
}
/**
* 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.
*
@ -1102,6 +1140,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.
*

View file

@ -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);

View file

@ -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);