The branch, master has been updated via dfedbae testtools: Import newer upstream revision. via 1fc1be4 Fix regf.idl, subkey and rootkey types were switched. via 7efcb3c Fix file corruption (non-updated header) on new allocation. via d0cef92 Fix crash when no subkeys exist. Fix writing outside of buffer error by regf backend. via 2c3f560 Add python bindings for open_hive function to be able to load REGF files. from 5d80710 s4/fsmo: Naming master support added
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit dfedbaeb055acb0d7abf74b9534308149a018ee4 Author: Jelmer Vernooij <jel...@samba.org> Date: Sun Sep 19 12:29:42 2010 -0700 testtools: Import newer upstream revision. This fixes (among other things) a warning during 'make test' on systems with Python 2.6. commit 1fc1be4685667f95e855fd2f781651c341e06fbd Author: wi...@baanhofman.nl <wi...@baanhofman.nl> Date: Mon Aug 30 12:17:41 2010 +0200 Fix regf.idl, subkey and rootkey types were switched. Signed-off-by: Jelmer Vernooij <jel...@samba.org> commit 7efcb3ca66b12972de3707164c7bd415619a4bb8 Author: wi...@baanhofman.nl <wi...@baanhofman.nl> Date: Mon Jul 26 23:00:43 2010 +0200 Fix file corruption (non-updated header) on new allocation. Also fixes debug messages to use hex offsets. Signed-off-by: Jelmer Vernooij <jel...@samba.org> commit d0cef92532f7c943e1c70d49ed96f090235b928e Author: wi...@baanhofman.nl <wi...@baanhofman.nl> Date: Mon Jul 26 20:13:22 2010 +0200 Fix crash when no subkeys exist. Fix writing outside of buffer error by regf backend. Signed-off-by: Jelmer Vernooij <jel...@samba.org> commit 2c3f56098b0322db2e74e860a0f236fde9f74bbc Author: wi...@baanhofman.nl <wi...@baanhofman.nl> Date: Mon Jul 26 12:32:32 2010 +0200 Add python bindings for open_hive function to be able to load REGF files. Signed-off-by: Jelmer Vernooij <jel...@samba.org> ----------------------------------------------------------------------- Summary of changes: lib/testtools/NEWS | 45 +++++++++++++--------- lib/testtools/testtools/matchers.py | 9 ++++ lib/testtools/testtools/testcase.py | 29 +++++++------- lib/testtools/testtools/tests/test_testtools.py | 32 +++++++++++++-- source4/lib/registry/pyregistry.c | 47 +++++++++++++++++++++-- source4/lib/registry/regf.c | 40 ++++++++++++++----- source4/lib/registry/regf.idl | 4 +- 7 files changed, 153 insertions(+), 53 deletions(-) Changeset truncated at 500 lines: diff --git a/lib/testtools/NEWS b/lib/testtools/NEWS index dc5e6df..596df0d 100644 --- a/lib/testtools/NEWS +++ b/lib/testtools/NEWS @@ -4,6 +4,15 @@ testtools NEWS NEXT ~~~~ +Improvements +------------ + +* Code duplication between assertEqual and the matcher Equals has been removed. + +* In normal circumstances, a TestCase will no longer share details with clones + of itself. (Andrew Bennetts, bug #637725) + + 0.9.6 ~~~~~ @@ -17,32 +26,32 @@ patches and TestCase.assertEqual gives slightly nicer errors. Improvements ------------ - * 'TestCase.assertEqual' now formats errors a little more nicely, in the - style of bzrlib. +* 'TestCase.assertEqual' now formats errors a little more nicely, in the + style of bzrlib. - * Added `PlaceHolder` and `ErrorHolder`, TestCase-like objects that can be - used to add results to a `TestResult`. +* Added `PlaceHolder` and `ErrorHolder`, TestCase-like objects that can be + used to add results to a `TestResult`. - * 'Mismatch' now takes optional description and details parameters, so - custom Matchers aren't compelled to make their own subclass. +* 'Mismatch' now takes optional description and details parameters, so + custom Matchers aren't compelled to make their own subclass. - * jml added a built-in UTF8_TEXT ContentType to make it slightly easier to - add details to test results. See bug #520044. +* jml added a built-in UTF8_TEXT ContentType to make it slightly easier to + add details to test results. See bug #520044. - * Fix a bug in our built-in matchers where assertThat would blow up if any - of them failed. All built-in mismatch objects now provide get_details(). +* Fix a bug in our built-in matchers where assertThat would blow up if any + of them failed. All built-in mismatch objects now provide get_details(). - * New 'Is' matcher, which lets you assert that a thing is identical to - another thing. +* New 'Is' matcher, which lets you assert that a thing is identical to + another thing. - * New 'LessThan' matcher which lets you assert that a thing is less than - another thing. +* New 'LessThan' matcher which lets you assert that a thing is less than + another thing. - * TestCase now has a 'patch()' method to make it easier to monkey-patching - objects in tests. See the manual for more information. Fixes bug #310770. +* TestCase now has a 'patch()' method to make it easier to monkey-patching + objects in tests. See the manual for more information. Fixes bug #310770. - * MultiTestResult methods now pass back return values from the results it - forwards to. +* MultiTestResult methods now pass back return values from the results it + forwards to. 0.9.5 ~~~~~ diff --git a/lib/testtools/testtools/matchers.py b/lib/testtools/testtools/matchers.py index 6a4c82a..61b5bd7 100644 --- a/lib/testtools/testtools/matchers.py +++ b/lib/testtools/testtools/matchers.py @@ -25,6 +25,7 @@ __all__ = [ import doctest import operator +from pprint import pformat class Matcher(object): @@ -178,6 +179,14 @@ class _BinaryMismatch(Mismatch): self.other = other def describe(self): + left = repr(self.expected) + right = repr(self.other) + if len(left) + len(right) > 70: + return "%s:\nreference = %s\nactual = %s\n" % ( + self._mismatch_string, pformat(self.expected), + pformat(self.other)) + else: + return "%s %s %s" % (left, self._mismatch_string,right) return "%r %s %r" % (self.expected, self._mismatch_string, self.other) diff --git a/lib/testtools/testtools/testcase.py b/lib/testtools/testtools/testcase.py index 48eec71..959c129 100644 --- a/lib/testtools/testtools/testcase.py +++ b/lib/testtools/testtools/testcase.py @@ -17,13 +17,16 @@ try: except ImportError: wraps = None import itertools -from pprint import pformat import sys import types import unittest from testtools import content from testtools.compat import advance_iterator +from testtools.matchers import ( + Annotate, + Equals, + ) from testtools.monkey import patch from testtools.runtest import RunTest from testtools.testresult import TestResult @@ -81,7 +84,9 @@ class TestCase(unittest.TestCase): self._traceback_id_gen = itertools.count(0) self.__setup_called = False self.__teardown_called = False - self.__details = {} + # __details is lazy-initialized so that a constructed-but-not-run + # TestCase is safe to use with clone_test_with_new_id. + self.__details = None self.__RunTest = kwargs.get('runTest', RunTest) self.__exception_handlers = [] self.exception_handlers = [ @@ -114,6 +119,8 @@ class TestCase(unittest.TestCase): :param content_object: The content object for this detail. See testtools.content for more detail. """ + if self.__details is None: + self.__details = {} self.__details[name] = content_object def getDetails(self): @@ -121,6 +128,8 @@ class TestCase(unittest.TestCase): For more details see pydoc testtools.TestResult. """ + if self.__details is None: + self.__details = {} return self.__details def patch(self, obj, attribute, value): @@ -230,18 +239,10 @@ class TestCase(unittest.TestCase): :param observed: The observed value. :param message: An optional message to include in the error. """ - try: - return super(TestCase, self).assertEqual(expected, observed) - except self.failureException: - lines = [] - if message: - lines.append(message) - lines.extend( - ["not equal:", - "a = %s" % pformat(expected), - "b = %s" % pformat(observed), - '']) - self.fail('\n'.join(lines)) + matcher = Equals(expected) + if message: + matcher = Annotate(message, matcher) + self.assertThat(observed, matcher) failUnlessEqual = assertEquals = assertEqual diff --git a/lib/testtools/testtools/tests/test_testtools.py b/lib/testtools/testtools/tests/test_testtools.py index 9edc5a5..5dfb355 100644 --- a/lib/testtools/testtools/tests/test_testtools.py +++ b/lib/testtools/testtools/tests/test_testtools.py @@ -461,6 +461,15 @@ class TestAssertions(TestCase): 'a = %s' % pformat(a), 'b = %s' % pformat(b), '']) + expected_error = '\n'.join([ + 'Match failed. Matchee: "%r"' % b, + 'Matcher: Annotate(%r, Equals(%r))' % (message, a), + 'Difference: !=:', + 'reference = %s' % pformat(a), + 'actual = %s' % pformat(b), + ': ' + message, + '' + ]) self.assertFails(expected_error, self.assertEqual, a, b, message) self.assertFails(expected_error, self.assertEquals, a, b, message) self.assertFails(expected_error, self.failUnlessEqual, a, b, message) @@ -468,11 +477,12 @@ class TestAssertions(TestCase): def test_assertEqual_formatting_no_message(self): a = "cat" b = "dog" - expected_error = '\n'.join( - ['not equal:', - 'a = %s' % pformat(a), - 'b = %s' % pformat(b), - '']) + expected_error = '\n'.join([ + 'Match failed. Matchee: "dog"', + 'Matcher: Equals(\'cat\')', + 'Difference: \'cat\' != \'dog\'', + '' + ]) self.assertFails(expected_error, self.assertEqual, a, b) self.assertFails(expected_error, self.assertEquals, a, b) self.assertFails(expected_error, self.failUnlessEqual, a, b) @@ -760,6 +770,18 @@ class TestCloneTestWithNewId(TestCase): self.assertEqual(oldName, test.id(), "the original test instance should be unchanged.") + def test_cloned_testcase_does_not_share_details(self): + """A cloned TestCase does not share the details dict.""" + class Test(TestCase): + def test_foo(self): + self.addDetail( + 'foo', content.Content('text/plain', lambda: 'foo')) + orig_test = Test('test_foo') + cloned_test = clone_test_with_new_id(orig_test, self.getUniqueString()) + orig_test.run(unittest.TestResult()) + self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes()) + self.assertEqual(None, cloned_test.getDetails().get('foo')) + class TestDetailsProvided(TestWithDetails): diff --git a/source4/lib/registry/pyregistry.c b/source4/lib/registry/pyregistry.c index 7f4f833..1373ed8 100644 --- a/source4/lib/registry/pyregistry.c +++ b/source4/lib/registry/pyregistry.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. Samba utility functions Copyright (C) Jelmer Vernooij <jel...@samba.org> 2008 + Copyright (C) Wilco Baan Hofman <wi...@baanhofman.nl> 2010 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 @@ -238,16 +239,53 @@ static PyMethodDef hive_key_methods[] = { { NULL } }; -static PyObject *hive_open(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - /* reg_open_hive */ +static PyObject *hive_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { Py_RETURN_NONE; } +static PyObject *py_open_hive(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + const char *kwnames[] = { "location", "lp_ctx", "session_info", "credentials", NULL }; + WERROR result; + struct loadparm_context *lp_ctx; + PyObject *py_lp_ctx, *py_session_info, *py_credentials; + struct auth_session_info *session_info; + struct cli_credentials *credentials; + char *location; + struct hive_key *hive_key; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOO", + discard_const_p(char *, kwnames), + &location, + &py_lp_ctx, &py_session_info, + &py_credentials)) + return NULL; + + lp_ctx = lpcfg_from_py_object(NULL, py_lp_ctx); /* FIXME: leaky */ + if (lp_ctx == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); + return NULL; + } + + credentials = cli_credentials_from_py_object(py_credentials); + if (credentials == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected credentials"); + return NULL; + } + session_info = NULL; + + result = reg_open_hive(NULL, location, session_info, credentials, + tevent_context_init(NULL), + lp_ctx, &hive_key); + PyErr_WERROR_IS_ERR_RAISE(result); + + return py_talloc_steal(&PyHiveKey, hive_key); +} + PyTypeObject PyHiveKey = { .tp_name = "HiveKey", .tp_methods = hive_key_methods, - .tp_new = hive_open, + .tp_new = hive_new, .tp_basicsize = sizeof(py_talloc_Object), .tp_dealloc = py_talloc_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, @@ -396,6 +434,7 @@ static PyMethodDef py_registry_methods[] = { { "open_directory", py_open_directory, METH_VARARGS, "open_dir(location) -> key" }, { "create_directory", py_create_directory, METH_VARARGS, "create_dir(location) -> key" }, { "open_ldb", (PyCFunction)py_open_ldb_file, METH_VARARGS|METH_KEYWORDS, "open_ldb(location, session_info=None, credentials=None, loadparm_context=None) -> key" }, + { "open_hive", (PyCFunction)py_open_hive, METH_VARARGS|METH_KEYWORDS, "open_hive(location, session_info=None, credentials=None, loadparm_context=None) -> key" }, { "str_regtype", py_str_regtype, METH_VARARGS, "str_regtype(int) -> str" }, { "get_predef_name", py_get_predef_name, METH_VARARGS, "get_predef_name(hkey) -> str" }, { NULL } diff --git a/source4/lib/registry/regf.c b/source4/lib/registry/regf.c index cfbaadd..b62109e 100644 --- a/source4/lib/registry/regf.c +++ b/source4/lib/registry/regf.c @@ -110,7 +110,7 @@ static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset) hbin = hbin_by_offset(data, offset, &rel_offset); if (hbin == NULL) { - DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset)); + DEBUG(1, ("Can't find HBIN at 0x%04x\n", offset)); return ret; } @@ -216,6 +216,8 @@ static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size, if (data->hbins[i] == NULL) { DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n", size)); + + /* Add extra hbin block */ data->hbins = talloc_realloc(data, data->hbins, struct hbin_block *, i+2); hbin = talloc(data->hbins, struct hbin_block); @@ -224,17 +226,22 @@ static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size, data->hbins[i] = hbin; data->hbins[i+1] = NULL; + /* Set hbin data */ hbin->HBIN_ID = talloc_strdup(hbin, "hbin"); hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next); hbin->offset_to_next = 0x1000; hbin->unknown[0] = 0; - hbin->unknown[0] = 0; + hbin->unknown[1] = 0; unix_to_nt_time(&hbin->last_change, time(NULL)); hbin->block_size = hbin->offset_to_next; hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20); + /* Update the regf header */ + data->header->last_block += hbin->offset_to_next; - rel_offset = 0x0; + /* Set the next block to it's proper size and set the + * rel_offset for this block */ SIVAL(hbin->data, size, hbin->block_size - size - 0x20); + rel_offset = 0x0; } /* Set size and mark as used */ @@ -314,7 +321,7 @@ static void hbin_free (struct regf_data *data, uint32_t offset) size = -size; /* If the next block is free, merge into big free block */ - if (rel_offset + size < hbin->offset_to_next) { + if (rel_offset + size < hbin->offset_to_next - 0x20) { next_size = IVALS(hbin->data, rel_offset+size); if (next_size > 0) { size += next_size; @@ -489,7 +496,7 @@ static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx, if (!hbin_get_tdr(regf, offset, nk, (tdr_pull_fn_t)tdr_pull_nk_block, nk)) { - DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset)); + DEBUG(0, ("Unable to find HBIN data for offset 0x%x\n", offset)); return NULL; } @@ -519,7 +526,8 @@ static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key, tmp = hbin_get(regf, private_data->nk->values_offset); if (!tmp.data) { - DEBUG(0, ("Unable to find value list\n")); + DEBUG(0, ("Unable to find value list at 0x%x\n", + private_data->nk->values_offset)); return WERR_GENERAL_FAILURE; } @@ -534,7 +542,7 @@ static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key, if (!hbin_get_tdr(regf, vk_offset, vk, (tdr_pull_fn_t)tdr_pull_vk_block, vk)) { - DEBUG(0, ("Unable to get VK block at %d\n", vk_offset)); + DEBUG(0, ("Unable to get VK block at 0x%x\n", vk_offset)); talloc_free(vk); return WERR_GENERAL_FAILURE; } @@ -606,9 +614,15 @@ static WERROR regf_get_subkey_by_index(TALLOC_CTX *ctx, if (idx >= nk->num_subkeys) return WERR_NO_MORE_ITEMS; + /* Make sure that we don't crash if the key is empty */ + if (nk->subkeys_offset == -1) { + return WERR_NO_MORE_ITEMS; + } + data = hbin_get(private_data->hive, nk->subkeys_offset); if (!data.data) { - DEBUG(0, ("Unable to find subkey list\n")); + DEBUG(0, ("Unable to find subkey list at 0x%x\n", + nk->subkeys_offset)); return WERR_GENERAL_FAILURE; } @@ -845,6 +859,11 @@ static WERROR regf_get_subkey_by_name(TALLOC_CTX *ctx, struct nk_block *nk = private_data->nk; uint32_t key_off = 0; + /* Make sure that we don't crash if the key is empty */ + if (nk->subkeys_offset == -1) { + return WERR_BADFILE; + } + data = hbin_get(private_data->hive, nk->subkeys_offset); if (!data.data) { DEBUG(0, ("Unable to find subkey list\n")); @@ -1739,7 +1758,7 @@ static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent, if (!hbin_get_tdr(regf, regf->header->data_offset, root, (tdr_pull_fn_t)tdr_pull_nk_block, root)) { - DEBUG(0, ("Unable to find HBIN data for offset %d\n", + DEBUG(0, ("Unable to find HBIN data for offset 0x%x\n", regf->header->data_offset)); return WERR_GENERAL_FAILURE; } @@ -1764,6 +1783,7 @@ static WERROR regf_add_key(TALLOC_CTX *ctx, const struct hive_key *parent, *ret = (struct hive_key *)regf_get_key(ctx, regf, offset); + DEBUG(9, ("Storing key %s\n", name)); return regf_save_hbin(private_data->hive); } @@ -1789,7 +1809,7 @@ static WERROR regf_set_value(struct hive_key *key, const char *name, if (!hbin_get_tdr(regf, tmp_vk_offset, private_data, (tdr_pull_fn_t)tdr_pull_vk_block, &vk)) { - DEBUG(0, ("Unable to get VK block at %d\n", + DEBUG(0, ("Unable to get VK block at 0x%x\n", tmp_vk_offset)); return WERR_GENERAL_FAILURE; } diff --git a/source4/lib/registry/regf.idl b/source4/lib/registry/regf.idl index fd58ad2..064aaf0 100644 --- a/source4/lib/registry/regf.idl +++ b/source4/lib/registry/regf.idl @@ -74,8 +74,8 @@ interface regf }; [noprint] enum reg_key_type { - REG_ROOT_KEY = 0x20, - REG_SUB_KEY = 0x2C, + REG_ROOT_KEY = 0x2C, + REG_SUB_KEY = 0x20, REG_SYM_LINK = 0x10 }; -- Samba Shared Repository