From baa776b7fb4066a2ee540d87ff8d76a6f443f7bc Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Wed, 18 Feb 2015 13:23:54 +0100
Subject: [PATCH 01/16] Add tests for ChecksumGenerator (chsgen)
This patch adds tests for calling "cynara-db-chsgen" executable.
Following call scenarios are checked:
* no filename,
* create checksum records for primary database contents,
* create checksum records for backup database contents.
Change-Id: I398f6865610598ab558b22a9cf3cdc620dc057b8
---
test/CMakeLists.txt | 6 +-
test/chsgen/ChsgenCommandlineTest.h | 31 +++++++++
test/chsgen/checksumgenerator.cpp | 121 ++++++++++++++++++++++++++++++++++++
3 files changed, 157 insertions(+), 1 deletion(-)
create mode 100644 test/chsgen/ChsgenCommandlineTest.h
create mode 100644 test/chsgen/checksumgenerator.cpp
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index fe62294..450993f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -49,6 +49,7 @@ SET(CYNARA_SOURCES_FOR_TESTS
${CYNARA_SRC}/common/types/PolicyDescription.cpp
${CYNARA_SRC}/common/types/PolicyResult.cpp
${CYNARA_SRC}/common/types/PolicyType.cpp
+ ${CYNARA_SRC}/chsgen/ChecksumGenerator.cpp
${CYNARA_SRC}/cyad/AdminPolicyParser.cpp
${CYNARA_SRC}/cyad/CommandlineParser/CmdlineErrors.cpp
${CYNARA_SRC}/cyad/CommandlineParser/CmdlineOpts.cpp
@@ -71,6 +72,7 @@ SET(CYNARA_SOURCES_FOR_TESTS
SET(CYNARA_TESTS_SOURCES
TestEventListenerProxy.cpp
+ chsgen/checksumgenerator.cpp
common/exceptions/bucketrecordcorrupted.cpp
common/protocols/admin/admincheckrequest.cpp
common/protocols/admin/admincheckresponse.cpp
@@ -121,6 +123,8 @@ ADD_EXECUTABLE(${TARGET_CYNARA_TESTS}
)
TARGET_LINK_LIBRARIES(${TARGET_CYNARA_TESTS}
- ${PKGS_LDFLAGS} ${PKGS_LIBRARIES}
+ ${PKGS_LDFLAGS}
+ ${PKGS_LIBRARIES}
+ crypt
)
INSTALL(TARGETS ${TARGET_CYNARA_TESTS} DESTINATION ${BIN_INSTALL_DIR})
diff --git a/test/chsgen/ChsgenCommandlineTest.h b/test/chsgen/ChsgenCommandlineTest.h
new file mode 100644
index 0000000..cbca399
--- /dev/null
+++ b/test/chsgen/ChsgenCommandlineTest.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file test/chsgen/ChsgenCommandlineTest.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Fixture for ChecksumGenerator tests
+ */
+
+#ifndef TEST_CHSGEN_CHSGENCOMMANDLINETEST_H_
+#define TEST_CHSGEN_CHSGENCOMMANDLINETEST_H_
+
+#include
+
+class ChsgenCommandlineTest : public QuietCommandlineTest {
+};
+
+#endif /* TEST_CHSGEN_CHSGENCOMMANDLINETEST_H_ */
diff --git a/test/chsgen/checksumgenerator.cpp b/test/chsgen/checksumgenerator.cpp
new file mode 100644
index 0000000..1d390d6
--- /dev/null
+++ b/test/chsgen/checksumgenerator.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file test/chsgen/checksumgenerator.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Tests of ChecksumGenerator
+ */
+
+#include
+
+#include
+
+#include
+
+#include
+
+#include "ChsgenCommandlineTest.h"
+
+namespace {
+
+const std::string execName("./cynara-db-chsgen");
+const std::string backupFilenameSuffix(Cynara::PathConfig::StoragePath::backupFilenameSuffix);
+const char fieldSeparator(Cynara::PathConfig::StoragePath::fieldSeparator);
+
+} // namespace
+
+/**
+ * @brief Verify if passing no filenames to checksum generator returns error message
+ * @test Expected result:
+ * - CYNARA_API_INVALID_COMMANDLINE_PARAM returned from checksum generator
+ * - empty output stream
+ * - message from caught exception in error stream
+ */
+TEST_F(ChsgenCommandlineTest, noFile) {
+ using ::testing::StartsWith;
+
+ std::string err;
+ std::string out;
+
+ clearOutput();
+ prepare_argv({ execName });
+
+ Cynara::ChecksumGenerator chsgen(this->argc(), this->argv());
+ const auto ret = chsgen.run();
+ getOutput(out, err);
+
+ ASSERT_EQ(CYNARA_API_INVALID_COMMANDLINE_PARAM, ret);
+ ASSERT_TRUE(out.empty());
+ ASSERT_THAT(err, StartsWith("File " + std::string() + " not found or corrupted badly"));
+}
+
+/**
+ * @brief Verify if checksum generator returns valid records
+ * @test Expected result:
+ * - CYNARA_API_SUCCESS returned from checksum generator
+ * - valid record in output stream
+ * - empty error stream
+ */
+TEST_F(ChsgenCommandlineTest, recordGeneration) {
+ using ::testing::StartsWith;
+
+ std::string err;
+ std::string out;
+
+ for (const std::string &file : { "_", "buckets" }) {
+ clearOutput();
+ prepare_argv({ execName, std::string(CYNARA_TESTS_DIR) + "/db3/" + file });
+ SCOPED_TRACE(file);
+
+ Cynara::ChecksumGenerator chsgen(this->argc(), this->argv());
+ const auto ret = chsgen.run();
+ getOutput(out, err);
+
+ ASSERT_EQ(CYNARA_API_SUCCESS, ret);
+ ASSERT_THAT(out, StartsWith(file + fieldSeparator + "$1$"));
+ ASSERT_TRUE(err.empty());
+ }
+}
+
+/**
+ * @brief Verify if checksum generator returns valid records for backup files
+ * @test Expected result:
+ * - CYNARA_API_SUCCESS returned from checksum generator
+ * - valid record in output stream
+ * - empty error stream
+ */
+TEST_F(ChsgenCommandlineTest, suffixErasing) {
+ using ::testing::StartsWith;
+
+ std::string err;
+ std::string out;
+
+ for (const std::string &file : { "_", "_additional", "buckets" }) {
+ clearOutput();
+ prepare_argv({ execName,
+ std::string(CYNARA_TESTS_DIR) + "/db6/" + file + backupFilenameSuffix });
+ SCOPED_TRACE(file);
+
+ Cynara::ChecksumGenerator chsgen(this->argc(), this->argv());
+ const auto ret = chsgen.run();
+ getOutput(out, err);
+
+ ASSERT_EQ(CYNARA_API_SUCCESS, ret);
+ ASSERT_THAT(out, StartsWith(file + fieldSeparator + "$1$"));
+ ASSERT_TRUE(err.empty());
+ }
+}
--
2.7.4
From 0cbbe1c7b7e7ffce65d5edc3dcca0c6055109cf0 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Wed, 11 Feb 2015 16:00:12 +0100
Subject: [PATCH 02/16] Refactorize migration tool
This refactoring run deals with:
* unintuitive naming,
* late input validation,
* passing only parts of input during option parsing,
* unconsistent comments.
Additionally, this patch:
* adds possiblity to install database in a custom directory,
* removes possibility of removing whole Cynara's state directory during
deinstallation - now only database is removed by migration tool.
Change-Id: I59e429d93812861ca9c32f201ed0056f753cbc25
---
migration/cynara-db-migration | 55 ++++++++++++++++++++++++++++---------------
1 file changed, 36 insertions(+), 19 deletions(-)
diff --git a/migration/cynara-db-migration b/migration/cynara-db-migration
index 5ab6409..46c6df0 100644
--- a/migration/cynara-db-migration
+++ b/migration/cynara-db-migration
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
STATE_PATH='/var/cynara'
DB_DIR='db'
INDEX_NAME='buckets'
-DEFAULT_NAME='_'
+DEFAULT_BUCKET_NAME='_'
DENY_POLICY=';0x0;'
##### Variables, with default values (optional)
@@ -40,22 +40,25 @@ NEW_VERSION=
##### Functions
parse_opts() {
- while getopts ":f:t:u:g:l:" opt; do
+ while getopts ":f:t:p:u:g:l:" opt; do
case $opt in
f )
- OLD_VERSION=${OPTARG}
+ OLD_VERSION="${OPTARG}"
;;
t )
- NEW_VERSION=${OPTARG}
+ NEW_VERSION="${OPTARG}"
+ ;;
+ p )
+ STATE_PATH="${OPTARG}"
;;
u )
- CYNARA_USER=${OPTARG}
+ CYNARA_USER="${OPTARG}"
;;
g )
- CYNARA_GROUP=${OPTARG}
+ CYNARA_GROUP="${OPTARG}"
;;
l )
- SMACK_LABEL=${OPTARG}
+ SMACK_LABEL="${OPTARG}"
;;
\? )
echo "Invalid option: -$OPTARG" >&2
@@ -69,17 +72,13 @@ parse_opts() {
done
}
-create_db() {
- if [ -z ${NEW_VERSION} ]; then
- failure
- fi
-
- # Create Cynara's database directory:
+minimal_db() {
+ # Create Cynara's database directory
mkdir -p ${STATE_PATH}/${DB_DIR}
# Create contents of minimal database: first index file, then default bucket
echo ${DENY_POLICY} > ${STATE_PATH}/${DB_DIR}/${INDEX_NAME}
- touch ${STATE_PATH}/${DB_DIR}/${DEFAULT_NAME}
+ touch ${STATE_PATH}/${DB_DIR}/${DEFAULT_BUCKET_NAME}
# Set proper permissions for newly created database
chown -R ${CYNARA_USER}:${CYNARA_GROUP} ${STATE_PATH}/${DB_DIR}
@@ -89,6 +88,14 @@ create_db() {
chsmack -a ${SMACK_LABEL} ${STATE_PATH}/${DB_DIR}/*
}
+install_db() {
+ if [ -z ${NEW_VERSION} ] ; then
+ failure
+ fi
+
+ minimal_db
+}
+
migrate_db() {
if [ -z ${OLD_VERSION} -o -z ${NEW_VERSION} ]; then
failure
@@ -96,7 +103,8 @@ migrate_db() {
# Create minimal database if there was none:
if [ ! -d "${STATE_PATH}/${DB_DIR}" ]; then
- create_db
+ install_db
+ exit_success
fi
}
@@ -105,7 +113,7 @@ remove_db() {
failure
fi
- rm -rf ${STATE_PATH}
+ rm -rf "${STATE_PATH}/${DB_DIR}"
}
usage() {
@@ -115,13 +123,14 @@ Usage: $0 COMMAND OPTIONS
This script installs, migrates to another version or removes Cynara's policies database
Commands:
- upgrade (up) migrate old data to new version of database structure
+ upgrade (up) migrate data to different version of database
install (in) create minimal database
uninstall (rm) remove database entirely
Options:
-f from Set old version of database (mandatory for upgrade and uninstall)
-t to Set new version of database (mandatory for upgrade and install)
+ -p path Set path for storing database (default: /var/cynara)
-u user Set database owner (default: cynara)
-g group Set database group (default: cynara)
-l label Set SMACK label for database (default: System)
@@ -131,9 +140,17 @@ EOF
failure() {
usage
+ exit_failure
+}
+
+exit_failure() {
exit 1
}
+exit_success() {
+ exit 0
+}
+
##### Main
if [ 0 -eq $# ]; then
@@ -149,7 +166,7 @@ case $1 in
"in" | "install" )
shift $OPTIND
parse_opts "$@"
- create_db
+ install_db
;;
"rm" | "uninstall" )
shift $OPTIND
--
2.7.4
From 3cdfeec14c8db2a11721aa7b71c2d689289c390a Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Mon, 9 Feb 2015 15:37:57 +0100
Subject: [PATCH 03/16] Add comparator for Semantic Versioning
Change-Id: I73b273465995b6246d20179395bdff1b4d1941f2
---
migration/cynara-db-migration | 46 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/migration/cynara-db-migration b/migration/cynara-db-migration
index 46c6df0..645d831 100644
--- a/migration/cynara-db-migration
+++ b/migration/cynara-db-migration
@@ -27,6 +27,11 @@ INDEX_NAME='buckets'
DEFAULT_BUCKET_NAME='_'
DENY_POLICY=';0x0;'
+# Return values for comparison
+LESS=-1
+EQUAL=0
+GREATER=1
+
##### Variables, with default values (optional)
CYNARA_USER='cynara'
@@ -39,6 +44,47 @@ NEW_VERSION=
##### Functions
+version_compare() {
+ local MAJOR1=
+ local MAJOR2=
+ local MINOR1=
+ local MINOR2=
+ local PATCH1=
+ local PATCH2=
+
+ # Parse
+ i=1
+ while [ 2 -ge $i ] ; do
+ eval "ARG=\$$i"
+ eval "MAJOR$i=${ARG%%.*}"
+ eval "TMP=${ARG#*.}"
+ eval "MINOR$i=${TMP%%.*}"
+ eval "PATCH$i=${ARG##*.}"
+ i=$(($i+1))
+ done
+
+ # Compare
+ if [ $MAJOR1 -lt $MAJOR2 ] ; then
+ echo "$LESS"
+ elif [ $MAJOR1 -eq $MAJOR2 ] ; then
+ if [ $MINOR1 -lt $MINOR2 ] ; then
+ echo "$LESS"
+ elif [ $MINOR1 -eq $MINOR2 ] ; then
+ if [ $PATCH1 -lt $PATCH2 ] ; then
+ echo "$LESS"
+ elif [ $PATCH1 -eq $PATCH2 ] ; then
+ echo "$EQUAL"
+ else
+ echo "$GREATER"
+ fi
+ else
+ echo "$GREATER"
+ fi
+ else
+ echo "$GREATER"
+ fi
+}
+
parse_opts() {
while getopts ":f:t:p:u:g:l:" opt; do
case $opt in
--
2.7.4
From 0bb80318f3edc278902bc5ff54c497ac1882be57 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Fri, 16 Jan 2015 11:16:56 +0100
Subject: [PATCH 04/16] Add support for checksums to migration tool
This patch also adds downgrade option to the migration tool.
Change-Id: If6a443172d52a78e8bfbf732e7eca38cb37f886f
---
migration/cynara-db-migration | 70 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/migration/cynara-db-migration b/migration/cynara-db-migration
index 645d831..d31897c 100644
--- a/migration/cynara-db-migration
+++ b/migration/cynara-db-migration
@@ -25,6 +25,8 @@ STATE_PATH='/var/cynara'
DB_DIR='db'
INDEX_NAME='buckets'
DEFAULT_BUCKET_NAME='_'
+CHECKSUM_NAME='checksum'
+GUARD_NAME='guard'
DENY_POLICY=';0x0;'
# Return values for comparison
@@ -32,6 +34,9 @@ LESS=-1
EQUAL=0
GREATER=1
+# Cynara version which introduced checksums
+CHS_INTRO_VERSION='0.6.0'
+
##### Variables, with default values (optional)
CYNARA_USER='cynara'
@@ -118,6 +123,41 @@ parse_opts() {
done
}
+generate_checksums() {
+ # Output file
+ CHECKSUMS="${STATE_PATH}/${DB_DIR}/${CHECKSUM_NAME}"
+ GUARD="${STATE_PATH}/${DB_DIR}/${GUARD_NAME}"
+ WILDCARD="*"
+
+ # Check if checksums should be generated from backup
+ if [ -e $GUARD ] ; then
+ WILDCARD="${WILDCARD}~"
+
+ # Database will be read from backup at next load
+ CHECKSUMS="${CHECKSUMS}~"
+ fi
+
+ # Mimic opening in truncate mode
+ echo -n "" > "${CHECKSUMS}"
+
+ # Actual checksums generation
+ for FILE in $(find ${STATE_PATH}/${DB_DIR}/${WILDCARD} -type f ! -name "${CHECKSUM_NAME}*" \
+ ! -name "${GUARD_NAME}"); do
+ CHECKSUM="$(/usr/sbin/cynara-db-chsgen ${FILE})"
+ if [ 0 -eq $? ] ; then
+ echo "${CHECKSUM}" >> ${CHECKSUMS}
+ else
+ exit_failure
+ fi
+ done
+
+ # Set proper permissions for newly created checksum file
+ chown -R ${CYNARA_USER}:${CYNARA_GROUP} ${CHECKSUMS}
+
+ # Set proper SMACK label for newly created checksum file
+ chsmack -a ${SMACK_LABEL} ${CHECKSUMS}
+}
+
minimal_db() {
# Create Cynara's database directory
mkdir -p ${STATE_PATH}/${DB_DIR}
@@ -134,12 +174,27 @@ minimal_db() {
chsmack -a ${SMACK_LABEL} ${STATE_PATH}/${DB_DIR}/*
}
+upgrade_db() {
+ # Add or update checksum file if necessary
+ if [ 0 -ge $(version_compare ${CHS_INTRO_VERSION} ${NEW_VERSION}) ] ; then
+ generate_checksums
+ fi
+}
+
+downgrade_db() {
+ # Remove checksum file if necessary
+ if [ 0 -lt $(version_compare ${CHS_INTRO_VERSION} ${NEW_VERSION}) ] ; then
+ rm "${STATE_PATH}/${DB_DIR}/${CHECKSUM_NAME}" > /dev/null 2>&1
+ fi
+}
+
install_db() {
if [ -z ${NEW_VERSION} ] ; then
failure
fi
minimal_db
+ upgrade_db
}
migrate_db() {
@@ -152,6 +207,21 @@ migrate_db() {
install_db
exit_success
fi
+
+ case $(version_compare ${OLD_VERSION} ${NEW_VERSION}) in
+ -1 )
+ upgrade_db
+ ;;
+ 0 )
+ :
+ # Same version given twice; take no action
+ ;;
+ 1 )
+ downgrade_db
+ ;;
+ * )
+ failure
+ esac
}
remove_db() {
--
2.7.4
From df2737b7eb40da782e0e1394284866331d54fe6a Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Tue, 24 Feb 2015 15:58:42 +0100
Subject: [PATCH 05/16] Add tests for migration tool
Change-Id: I2bdd88cd07646896b75ea36e7776b7fa1a449bd8
---
packaging/cynara.spec | 1 +
test/CMakeLists.txt | 4 +
test/db/db10_postchs_bcp/_~ | 0
test/db/db10_postchs_bcp/buckets~ | 1 +
test/db/db10_postchs_bcp/checksum~ | 2 +
test/db/db10_postchs_bcp/guard | 0
test/db/db7_prechs/_ | 0
test/db/db7_prechs/buckets | 1 +
test/db/db8_postchs/_ | 0
test/db/db8_postchs/buckets | 1 +
test/db/db8_postchs/checksum | 2 +
test/db/db9_prechs_bcp/_~ | 0
test/db/db9_prechs_bcp/buckets~ | 1 +
test/db/db9_prechs_bcp/guard | 0
test/tools/cynara-db-migration-tests | 218 +++++++++++++++++++++++++++++++++++
15 files changed, 231 insertions(+)
create mode 100644 test/db/db10_postchs_bcp/_~
create mode 100644 test/db/db10_postchs_bcp/buckets~
create mode 100644 test/db/db10_postchs_bcp/checksum~
create mode 100644 test/db/db10_postchs_bcp/guard
create mode 100644 test/db/db7_prechs/_
create mode 100644 test/db/db7_prechs/buckets
create mode 100644 test/db/db8_postchs/_
create mode 100644 test/db/db8_postchs/buckets
create mode 100644 test/db/db8_postchs/checksum
create mode 100644 test/db/db9_prechs_bcp/_~
create mode 100644 test/db/db9_prechs_bcp/buckets~
create mode 100644 test/db/db9_prechs_bcp/guard
create mode 100644 test/tools/cynara-db-migration-tests
diff --git a/packaging/cynara.spec b/packaging/cynara.spec
index 48d939a..3289855 100644
--- a/packaging/cynara.spec
+++ b/packaging/cynara.spec
@@ -337,6 +337,7 @@ fi
%files -n cynara-tests
%manifest cynara-tests.manifest
%attr(755,root,root) /usr/bin/cynara-tests
+%attr(755,root,root) /usr/bin/cynara-db-migration-tests
%attr(755,root,root) %{tests_dir}/db*/*
%dir %attr(755,root,root) %{tests_dir}/empty_db
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 450993f..d937d3c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -107,6 +107,8 @@ SET(CYNARA_TESTS_SOURCES
types/policykey.cpp
)
+SET(CYNARA_MIGRATION_TOOL_TESTS tools/cynara-db-migration-tests)
+
INCLUDE_DIRECTORIES(
${PKGS_INCLUDE_DIRS}
${CYNARA_SRC}/common
@@ -128,3 +130,5 @@ TARGET_LINK_LIBRARIES(${TARGET_CYNARA_TESTS}
crypt
)
INSTALL(TARGETS ${TARGET_CYNARA_TESTS} DESTINATION ${BIN_INSTALL_DIR})
+
+INSTALL(FILES ${CYNARA_MIGRATION_TOOL_TESTS} DESTINATION ${BIN_INSTALL_DIR})
diff --git a/test/db/db10_postchs_bcp/_~ b/test/db/db10_postchs_bcp/_~
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db10_postchs_bcp/buckets~ b/test/db/db10_postchs_bcp/buckets~
new file mode 100644
index 0000000..29ab987
--- /dev/null
+++ b/test/db/db10_postchs_bcp/buckets~
@@ -0,0 +1 @@
+;0x0;
diff --git a/test/db/db10_postchs_bcp/checksum~ b/test/db/db10_postchs_bcp/checksum~
new file mode 100644
index 0000000..63b55e0
--- /dev/null
+++ b/test/db/db10_postchs_bcp/checksum~
@@ -0,0 +1,2 @@
+_;$1$$qRPK7m23GJusamGpoGLby/
+buckets;$1$$6ZlVs5lw2nZgVmiw0BdY21
diff --git a/test/db/db10_postchs_bcp/guard b/test/db/db10_postchs_bcp/guard
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db7_prechs/_ b/test/db/db7_prechs/_
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db7_prechs/buckets b/test/db/db7_prechs/buckets
new file mode 100644
index 0000000..29ab987
--- /dev/null
+++ b/test/db/db7_prechs/buckets
@@ -0,0 +1 @@
+;0x0;
diff --git a/test/db/db8_postchs/_ b/test/db/db8_postchs/_
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db8_postchs/buckets b/test/db/db8_postchs/buckets
new file mode 100644
index 0000000..29ab987
--- /dev/null
+++ b/test/db/db8_postchs/buckets
@@ -0,0 +1 @@
+;0x0;
diff --git a/test/db/db8_postchs/checksum b/test/db/db8_postchs/checksum
new file mode 100644
index 0000000..63b55e0
--- /dev/null
+++ b/test/db/db8_postchs/checksum
@@ -0,0 +1,2 @@
+_;$1$$qRPK7m23GJusamGpoGLby/
+buckets;$1$$6ZlVs5lw2nZgVmiw0BdY21
diff --git a/test/db/db9_prechs_bcp/_~ b/test/db/db9_prechs_bcp/_~
new file mode 100644
index 0000000..e69de29
diff --git a/test/db/db9_prechs_bcp/buckets~ b/test/db/db9_prechs_bcp/buckets~
new file mode 100644
index 0000000..29ab987
--- /dev/null
+++ b/test/db/db9_prechs_bcp/buckets~
@@ -0,0 +1 @@
+;0x0;
diff --git a/test/db/db9_prechs_bcp/guard b/test/db/db9_prechs_bcp/guard
new file mode 100644
index 0000000..e69de29
diff --git a/test/tools/cynara-db-migration-tests b/test/tools/cynara-db-migration-tests
new file mode 100644
index 0000000..c6ea3d8
--- /dev/null
+++ b/test/tools/cynara-db-migration-tests
@@ -0,0 +1,218 @@
+#!/bin/sh
+#
+# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,`
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# @file test/tools/cynara-db-migration-tests
+# @author Pawel Wieczorek
+# @brief Tests of migration tool for Cynara's database
+#
+
+##### Constants (these must not be modified by shell)
+
+# Paths
+TESTS_DIR='/tmp/cynara-db-migration-tests'
+PATTERNS_DIR='/usr/share/cynara/tests'
+MIGRATE='/usr/sbin/cynara-db-migration'
+
+# Names
+DB_DIR='db'
+LOG_FILE='output.log'
+FAIL_FILE='fail.log'
+
+# Various Cynara versions
+CHS_INTRO_VERSION='0.6.0'
+PRECHS_HIGH_VERSION='0.4.2'
+PRECHS_LOW_VERSION='0.2.4'
+POSTCHS_HIGH_VERSION='4.2.0'
+POSTCHS_LOW_VERSION='2.4.0'
+
+# Messages
+MIGRATE_FAIL_MSG="$MIGRATE failed."
+COMPARE_FAIL_MSG="Mismatch in file"
+DB_STILL_EXISTS_MSG="Database directory still exists."
+
+# Status indicators
+SUCCESS=0
+FAILURE=1
+
+##### Variables, with default values (optional)
+
+TEST_CASE=0
+
+##### Functions
+
+fail_msg() {
+ local ID="$1"
+ local NAME="$2"
+ echo "Test $ID ($NAME) failed:"
+ cat "${TESTS_DIR}/${ID}/${FAIL_FILE}"
+}
+
+success_msg() {
+ local ID="$1"
+ local NAME="$2"
+ echo "Test $ID ($NAME) passed."
+}
+
+execute() {
+ ${MIGRATE} $1
+ echo $?
+}
+
+run() {
+ # Iterate test case ID
+ TEST_CASE=$(($TEST_CASE+1))
+
+ # Prepare environment
+ local ID=$TEST_CASE
+ local INITIAL="$1"
+ local PATTERN="$2"
+ local NAME="$3"
+ local STATE_PATH="${TESTS_DIR}/${ID}"
+
+ mkdir -p "$STATE_PATH"
+ if [ 'empty' != "$INITIAL" ] ; then
+ cp -a "${PATTERNS_DIR}/${INITIAL}" "${STATE_PATH}/${DB_DIR}"
+ fi
+
+ # Prepare error handling
+ local RUN_SUCCESS=$SUCCESS
+ local FAIL_REASON="${STATE_PATH}/${FAIL_FILE}"
+ echo -n "" > "$FAIL_REASON"
+
+ # Run command
+ local ARG="$4 -p $STATE_PATH"
+ local RET=$(execute "$ARG")
+
+ # Check results
+ if [ $SUCCESS -ne $RET ] ; then
+ # Migration tool failure
+ echo "$MIGRATE_FAIL_MSG" > "$FAIL_REASON"
+ else
+ # Clear logfile
+ local LOG="${STATE_PATH}/${LOG_FILE}"
+ echo -n "" > "$LOG"
+
+ if [ 'empty' = "$PATTERN" ] ; then
+ # No pattern - check if database directory was removed
+ if [ -d "${STATE_PATH}/${DB_DIR}" ] ; then
+ RUN_SUCCESS=$FAILURE
+ echo "" >> "$FAIL_REASON"
+ echo "$DB_STILL_EXISTS_MSG" >> "$FAIL_REASON"
+ fi
+ else
+ # Pattern given - compare it to generated database
+ for FILE in ${PATTERNS_DIR}/${PATTERN}/* ; do
+ diff ${FILE} ${STATE_PATH}/${DB_DIR}/${FILE##*\/} > "$LOG" 2>&1
+ if [ $SUCCESS -ne $? ] ; then
+ RUN_SUCCESS=$FAILURE
+ # Append comparison result to fail log
+ echo "" >> "$FAIL_REASON"
+ echo "${COMPARE_FAIL_MSG}: ${FILE##*\/}" >> "$FAIL_REASON"
+ cat "$LOG" >> "$FAIL_REASON"
+ fi
+ done
+ fi
+ fi
+
+ # Return results
+ if [ $SUCCESS -eq $RUN_SUCCESS ] ; then
+ success_msg "$ID" "$NAME"
+ else
+ fail_msg "$ID" "$NAME"
+ fi
+
+ # Clean up environment
+ rm -r "$STATE_PATH"
+}
+
+##### Main
+
+# How to add new test cases:
+#
+# run INITIAL_DB PATTERN_DB TEST_CASE_NAME MIGRATION_ARGS
+#
+# checking if database was removed: pass 'empty' as PATTERN_DB
+
+### Set up tests environment
+mkdir -p "$TESTS_DIR"
+
+# Test case 01: install minimal pre-checksum database
+run empty db7_prechs "inst_min_prechs" "install -t $PRECHS_LOW_VERSION"
+
+# Test case 02: install minimal post-checksum database
+run empty db8_postchs "inst_min_postchs" "install -t $POSTCHS_LOW_VERSION"
+
+# Test case 03: upgrade from pre-checksum to pre-checksum
+run db7_prechs db7_prechs "up_prechs_prechs" \
+ "upgrade -f $PRECHS_LOW_VERSION -t $PRECHS_HIGH_VERSION"
+
+# Test case 04: upgrade from pre-checksum to post-checksum
+run db7_prechs db8_postchs "up_prechs_postchs" \
+ "upgrade -f $PRECHS_LOW_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 05: upgrade from post-checksum to post-checksum
+run db8_postchs db8_postchs "up_postchs_postchs" \
+ "upgrade -f $POSTCHS_LOW_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 06: downgrade from pre-checksum to pre-checksum
+run db7_prechs db7_prechs "down_prechs_prechs" \
+ "upgrade -f $PRECHS_HIGH_VERSION -t $PRECHS_LOW_VERSION"
+
+# Test case 07: downgrade from post-checksum to pre-checksum
+run db8_postchs db7_prechs "down_postchs_prechs" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $PRECHS_LOW_VERSION"
+
+# Test case 08: downgrade from post-checksum to post-checksum
+run db8_postchs db8_postchs "down_postchs_postchs" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $POSTCHS_LOW_VERSION"
+
+# Test case 09: migrate to the same database version
+run db8_postchs db8_postchs "migr_same_ver" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 10: uninstall database
+run db7_prechs empty "uninst_db" "uninstall -f $PRECHS_LOW_VERSION"
+
+# Test case 11: upgrade from pre-checksum to pre-checksum (backups)
+run db9_prechs_bcp db9_prechs_bcp "up_prechs_prechs_bcp" \
+ "upgrade -f $PRECHS_LOW_VERSION -t $PRECHS_HIGH_VERSION"
+
+# Test case 12: upgrade from pre-checksum to post-checksum (backups)
+run db9_prechs_bcp db10_postchs_bcp "up_prechs_postchs_bcp" \
+ "upgrade -f $PRECHS_LOW_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 13: upgrade from post-checksum to post-checksum (backups)
+run db10_postchs_bcp db10_postchs_bcp "up_postchs_postchs_bcp" \
+ "upgrade -f $POSTCHS_LOW_VERSION -t $POSTCHS_HIGH_VERSION"
+
+# Test case 14: downgrade from backup pre-checksum to pre-checksum (backups)
+run db9_prechs_bcp db9_prechs_bcp "down_prechs_prechs_bcp" \
+ "upgrade -f $PRECHS_HIGH_VERSION -t $PRECHS_LOW_VERSION"
+
+# Test case 15: downgrade from backup post-checksum to pre-checksum (backups)
+run db10_postchs_bcp db9_prechs_bcp "down_postchs_prechs_bcp" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $PRECHS_LOW_VERSION"
+
+# Test case 16: downgrade from backup post-checksum to post-checksum (backups)
+run db10_postchs_bcp db10_postchs_bcp "down_postchs_postchs_bcp" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $POSTCHS_LOW_VERSION"
+
+# Test case 17: migrate to the same database version (backups)
+run db10_postchs_bcp db10_postchs_bcp "migr_same_ver_bcp" \
+ "upgrade -f $POSTCHS_HIGH_VERSION -t $POSTCHS_HIGH_VERSION"
+
+### Clean up tests environment
+rm -r "$TESTS_DIR"
--
2.7.4
From 2f2d8f10c0b96524c6380b18a89845016632a53b Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Fri, 5 Dec 2014 15:26:24 +0100
Subject: [PATCH 06/16] Extend ignored files list in integrity mechanism
Integrity mechanism will not remove file containing checksums even
though it is not listed in database index.
Change-Id: I1e587ecdad5abff47d78362394cc0ecdb1ecd4c4
---
src/storage/Integrity.cpp | 14 +++++++++++---
src/storage/Integrity.h | 3 +++
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/storage/Integrity.cpp b/src/storage/Integrity.cpp
index 82e8f5a..5dfa624 100644
--- a/src/storage/Integrity.cpp
+++ b/src/storage/Integrity.cpp
@@ -109,9 +109,8 @@ void Integrity::deleteNonIndexedFiles(BucketPresenceTester tester) {
while (errno = 0, (direntPtr = readdir(dirPtr)) != nullptr) {
std::string filename = direntPtr->d_name;
- //ignore all special files (working dir, parent dir, index)
- if ("." == filename || ".." == filename ||
- PathConfig::StoragePath::indexFilename == filename) {
+ //ignore all special files (working dir, parent dir, index, checksums)
+ if (isSpecialDirectory(filename) || isSpecialDatabaseEntry(filename)) {
continue;
}
@@ -236,4 +235,13 @@ void Integrity::deleteHardLink(const std::string &filename) {
}
}
+bool Integrity::isSpecialDirectory(const std::string &filename) {
+ return "." == filename || ".." == filename;
+}
+
+bool Integrity::isSpecialDatabaseEntry(const std::string &filename) {
+ return PathConfig::StoragePath::indexFilename == filename ||
+ PathConfig::StoragePath::checksumFilename == filename;
+}
+
} /* namespace Cynara */
diff --git a/src/storage/Integrity.h b/src/storage/Integrity.h
index d06eada..2917fb3 100644
--- a/src/storage/Integrity.h
+++ b/src/storage/Integrity.h
@@ -58,6 +58,9 @@ protected:
static void createHardLink(const std::string &oldName, const std::string &newName);
static void deleteHardLink(const std::string &filename);
+ static bool isSpecialDirectory(const std::string &filename);
+ static bool isSpecialDatabaseEntry(const std::string &filename);
+
private:
const std::string m_dbPath;
static const std::string m_indexFilename;
--
2.7.4
From 501306b6a09f74a644e620ebcdef42a3cbc3c10b Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Fri, 27 Feb 2015 10:50:52 +0100
Subject: [PATCH 07/16] Remove unwanted pointers (InMemoryStorageBackend)
Using pointers to helper classes (Integrity and, in future,
ChecksumValidator) is unnecessary and undesired. However, this forces
removal of InMemoryStorageBackend default constructor, as it cannot
initialize its helpers with valid arguments.
This patch also adjusts tests to the new constructor set and removes no
longer used typedef.
Change-Id: If0a41a75c16be6d55bdf3841ddb5190c388968af
---
src/storage/InMemoryStorageBackend.cpp | 16 +++++------
src/storage/InMemoryStorageBackend.h | 6 ++---
src/storage/Integrity.h | 3 ---
test/storage/inmemorystoragebackend/buckets.cpp | 14 +++++-----
.../inmemeorystoragebackendfixture.h | 3 ++-
.../inmemorystoragebackend.cpp | 31 +++++++++++-----------
test/storage/inmemorystoragebackend/search.cpp | 4 +--
7 files changed, 38 insertions(+), 39 deletions(-)
diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp
index 45b7874..a5e08b1 100644
--- a/src/storage/InMemoryStorageBackend.cpp
+++ b/src/storage/InMemoryStorageBackend.cpp
@@ -57,12 +57,12 @@ const std::string InMemoryStorageBackend::m_backupFilenameSuffix(
const std::string InMemoryStorageBackend::m_bucketFilenamePrefix(
PathConfig::StoragePath::bucketFilenamePrefix);
-InMemoryStorageBackend::InMemoryStorageBackend(const std::string &path) : m_dbPath(path) {
- m_integrity.reset(new Integrity(path));
+InMemoryStorageBackend::InMemoryStorageBackend(const std::string &path) : m_dbPath(path),
+ m_integrity(path) {
}
void InMemoryStorageBackend::load(void) {
- bool isBackupValid = m_integrity->backupGuardExists();
+ bool isBackupValid = m_integrity.backupGuardExists();
std::string bucketSuffix = "";
std::string indexFilename = m_dbPath + m_indexFilename;
@@ -104,9 +104,9 @@ void InMemoryStorageBackend::save(void) {
storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
this, std::placeholders::_1));
- m_integrity->syncDatabase(buckets(), true);
- m_integrity->createBackupGuard();
- m_integrity->revalidatePrimaryDatabase(buckets());
+ m_integrity.syncDatabase(buckets(), true);
+ m_integrity.createBackupGuard();
+ m_integrity.revalidatePrimaryDatabase(buckets());
//guard is removed during revalidation
}
@@ -265,10 +265,10 @@ std::shared_ptr InMemoryStorageBackend::bucketDumpStreamOpene
void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) {
if (isBackupValid) {
- m_integrity->revalidatePrimaryDatabase(buckets());
+ m_integrity.revalidatePrimaryDatabase(buckets());
}
//in case there were unnecessary files in db directory
- m_integrity->deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this,
+ m_integrity.deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this,
std::placeholders::_1));
}
diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h
index 723c61d..c9e63c2 100644
--- a/src/storage/InMemoryStorageBackend.h
+++ b/src/storage/InMemoryStorageBackend.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@ namespace Cynara {
class InMemoryStorageBackend : public StorageBackend {
public:
+ InMemoryStorageBackend() = delete;
InMemoryStorageBackend(const std::string &path);
virtual ~InMemoryStorageBackend() {};
@@ -64,7 +65,6 @@ public:
const PolicyKey &filter);
protected:
- InMemoryStorageBackend() {}
void openFileStream(std::shared_ptr stream, const std::string &filename);
std::shared_ptr bucketStreamOpener(const PolicyBucketId &bucketId,
const std::string &fileNameSuffix);
@@ -78,7 +78,7 @@ protected:
private:
std::string m_dbPath;
Buckets m_buckets;
- IntegrityUniquePtr m_integrity;
+ Integrity m_integrity;
static const std::string m_indexFilename;
static const std::string m_backupFilenameSuffix;
static const std::string m_bucketFilenamePrefix;
diff --git a/src/storage/Integrity.h b/src/storage/Integrity.h
index 2917fb3..569ca85 100644
--- a/src/storage/Integrity.h
+++ b/src/storage/Integrity.h
@@ -31,9 +31,6 @@
namespace Cynara {
-class Integrity;
-typedef std::unique_ptr IntegrityUniquePtr;
-
class Integrity
{
public:
diff --git a/test/storage/inmemorystoragebackend/buckets.cpp b/test/storage/inmemorystoragebackend/buckets.cpp
index f53b51c..d201d69 100644
--- a/test/storage/inmemorystoragebackend/buckets.cpp
+++ b/test/storage/inmemorystoragebackend/buckets.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ TEST_F(InMemeoryStorageBackendFixture, createBucket) {
using ::testing::ReturnRef;
using ::testing::IsEmpty;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -53,7 +53,7 @@ TEST_F(InMemeoryStorageBackendFixture, createBucket) {
TEST_F(InMemeoryStorageBackendFixture, updateBucket) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -69,7 +69,7 @@ TEST_F(InMemeoryStorageBackendFixture, updateBucket) {
TEST_F(InMemeoryStorageBackendFixture, updateNonexistentBucket) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -81,7 +81,7 @@ TEST_F(InMemeoryStorageBackendFixture, deleteBucket) {
using ::testing::ReturnRef;
using ::testing::IsEmpty;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -97,7 +97,7 @@ TEST_F(InMemeoryStorageBackendFixture, hasBucket) {
using ::testing::ReturnRef;
using ::testing::IsEmpty;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -111,7 +111,7 @@ TEST_F(InMemeoryStorageBackendFixture, hasBucket) {
TEST_F(InMemeoryStorageBackendFixture, deleteNonexistentBucket) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
diff --git a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h
index b671a0d..fbc523b 100644
--- a/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h
+++ b/test/storage/inmemorystoragebackend/inmemeorystoragebackendfixture.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -147,6 +147,7 @@ protected:
Cynara::Buckets m_buckets;
static const std::string m_indexFileName;
static const std::string m_backupFileNameSuffix;
+ static const std::string m_fakeDbPath;
//erase helper structures
Cynara::PolicyCollection m_fullPolicyCollection;
diff --git a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
index 8e19743..1c88335 100644
--- a/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
+++ b/test/storage/inmemorystoragebackend/inmemorystoragebackend.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,13 +40,14 @@
using namespace Cynara;
-const std::string InMemeoryStorageBackendFixture::m_indexFileName = "buckets";
-const std::string InMemeoryStorageBackendFixture::m_backupFileNameSuffix = "~";
+const std::string InMemeoryStorageBackendFixture::m_indexFileName("buckets");
+const std::string InMemeoryStorageBackendFixture::m_backupFileNameSuffix("~");
+const std::string InMemeoryStorageBackendFixture::m_fakeDbPath("/fake/database/path");
TEST_F(InMemeoryStorageBackendFixture, defaultPolicyIsDeny) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -65,7 +66,7 @@ TEST_F(InMemeoryStorageBackendFixture, deleteLinking) {
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.Times(4)
.WillRepeatedly(ReturnRef(m_buckets));
@@ -120,7 +121,7 @@ TEST_F(InMemeoryStorageBackendFixture, insertPolicy) {
using ::testing::UnorderedElementsAre;
using PredefinedPolicyType::ALLOW;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -136,7 +137,7 @@ TEST_F(InMemeoryStorageBackendFixture, insertPolicy) {
TEST_F(InMemeoryStorageBackendFixture, insertPolicyToNonexistentBucket) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -151,7 +152,7 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicy) {
using ::testing::ContainerEq;
using PredefinedPolicyType::ALLOW;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -184,7 +185,7 @@ TEST_F(InMemeoryStorageBackendFixture, deletePolicyFromNonexistentBucket) {
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillOnce(ReturnRef(m_buckets));
@@ -311,7 +312,7 @@ TEST_F(InMemeoryStorageBackendFixture, load_from_backup) {
TEST_F(InMemeoryStorageBackendFixture, erasePoliciesEmptyBase) {
using ::testing::ReturnRef;
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
@@ -345,7 +346,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesSingleBucket) {
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
@@ -380,7 +381,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesRecursiveNotLinkedBuckets) {
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
@@ -423,7 +424,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesRecursiveLinkedBuckets) {
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
@@ -473,7 +474,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesRecursiveLinkedBucketsNoBack
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
@@ -522,7 +523,7 @@ TEST_F(InMemeoryStorageBackendFixture, erasePoliciesNonRecursiveLinkedBuckets) {
for (const auto &filter : filters()) {
SCOPED_TRACE(filter.name());
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets()).WillRepeatedly(ReturnRef(m_buckets));
createBucket(bucketId);
diff --git a/test/storage/inmemorystoragebackend/search.cpp b/test/storage/inmemorystoragebackend/search.cpp
index cf6a419..46247a2 100644
--- a/test/storage/inmemorystoragebackend/search.cpp
+++ b/test/storage/inmemorystoragebackend/search.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ TEST_F(InMemeoryStorageBackendFixture, searchDefault) {
createBucket(defaultPolicyBucketId, policies);
// Just override buckets() accessor
- FakeInMemoryStorageBackend backend;
+ FakeInMemoryStorageBackend backend(m_fakeDbPath);
EXPECT_CALL(backend, buckets())
.WillRepeatedly(ReturnRef(m_buckets));
--
2.7.4
From ba47308b144e4321ebce79ecf837a1104b0d1d74 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Mon, 22 Dec 2014 16:18:41 +0100
Subject: [PATCH 08/16] Modify RecordCorruptedException class hierarchy
So far there was only one type of record Cynara could read from its
database. If any corruption was detected, BucketRecordCorruptedException
was thrown.
Now database will contain information about not only buckets and
policies, but also some metadata for them (in this case - checksums).
Need for exception superclass for handling corrupted records emerged.
Patch modifies exception class hierarchy and adds new exception type:
ChecksumRecordCorruptedException.
Change-Id: I3af6bd20b57e17ec31d766f138595920c7a413bd
---
.../exceptions/BucketRecordCorruptedException.h | 64 ++++------------
.../exceptions/ChecksumRecordCorruptedException.h | 57 ++++++++++++++
src/common/exceptions/RecordCorruptedException.h | 86 ++++++++++++++++++++++
3 files changed, 158 insertions(+), 49 deletions(-)
create mode 100644 src/common/exceptions/ChecksumRecordCorruptedException.h
create mode 100644 src/common/exceptions/RecordCorruptedException.h
diff --git a/src/common/exceptions/BucketRecordCorruptedException.h b/src/common/exceptions/BucketRecordCorruptedException.h
index a5ffb7d..e7ea604 100644
--- a/src/common/exceptions/BucketRecordCorruptedException.h
+++ b/src/common/exceptions/BucketRecordCorruptedException.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,82 +16,48 @@
/**
* @file src/common/exceptions/BucketRecordCorruptedException.h
* @author Aleksander Zdyb
+ * @author Pawel Wieczorek
* @version 1.0
* @brief Implementation of BucketRecordCorruptedException
*/
+
#ifndef SRC_COMMON_EXCEPTIONS_BUCKETRECORDCORRUPTEDEXCEPTION_H_
#define SRC_COMMON_EXCEPTIONS_BUCKETRECORDCORRUPTEDEXCEPTION_H_
#include
-#include
+#include
namespace Cynara {
-class BucketRecordCorruptedException : public DatabaseException {
+class BucketRecordCorruptedException : public RecordCorruptedException {
public:
- BucketRecordCorruptedException(void) = delete;
+ BucketRecordCorruptedException() = delete;
virtual ~BucketRecordCorruptedException() {};
- BucketRecordCorruptedException(const std::string &line)
- : m_lineNumber(0), m_line(line) {}
+ BucketRecordCorruptedException(const std::string &line) : RecordCorruptedException(line) {
+ setMessage(subtype());
+ }
BucketRecordCorruptedException withLineNumber(const size_t &lineNumber) const {
BucketRecordCorruptedException copy(*this);
copy.m_lineNumber = lineNumber;
- copy.m_message.clear();
+ copy.setMessage(copy.subtype());
return copy;
}
BucketRecordCorruptedException withFilename(const std::string &filename) const {
BucketRecordCorruptedException copy(*this);
copy.m_filename = filename;
- copy.m_message.clear();
+ copy.setMessage(copy.subtype());
return copy;
}
- virtual const std::string &message(void) const {
- if (m_message.empty()) {
- m_message = "Bucket record corrupted at"
- + formatedFilename()
- + formatedLineNumber()
- + ": <" + slicedLine() + ">";
- }
- return m_message;
- }
-
- const std::string &filename(void) const {
- return m_filename;
- }
-
- const std::string &line(void) const {
- return m_line;
- }
-
- size_t lineNumber(void) const {
- return m_lineNumber;
- }
-
-protected:
- inline std::string slicedLine(void) const {
- return m_line.substr(0, 50) + (m_line.size() > 50 ? "..." : "");
- }
-
- inline std::string formatedFilename(void) const {
- return m_filename.empty() ? " line" : " " + m_filename;
- }
-
- inline std::string formatedLineNumber(void) const {
- return m_lineNumber <= 0 ? ""
- : (m_filename.empty() ? " " : ":")
- + std::to_string(static_cast(m_lineNumber));
- }
-
private:
- size_t m_lineNumber;
- std::string m_line;
- std::string m_filename;
- mutable std::string m_message;
+ const std::string &subtype(void) {
+ static const std::string subtype("Bucket");
+ return subtype;
+ }
};
} /* namespace Cynara */
diff --git a/src/common/exceptions/ChecksumRecordCorruptedException.h b/src/common/exceptions/ChecksumRecordCorruptedException.h
new file mode 100644
index 0000000..84b81bc
--- /dev/null
+++ b/src/common/exceptions/ChecksumRecordCorruptedException.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file src/common/exceptions/ChecksumRecordCorruptedException.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Implementation of ChecksumRecordCorruptedException
+ */
+
+#ifndef SRC_COMMON_EXCEPTIONS_CHECKSUMRECORDCORRUPTEDEXCEPTION_H_
+#define SRC_COMMON_EXCEPTIONS_CHECKSUMRECORDCORRUPTEDEXCEPTION_H_
+
+#include
+
+#include
+
+namespace Cynara {
+
+class ChecksumRecordCorruptedException : public RecordCorruptedException {
+public:
+ ChecksumRecordCorruptedException() = delete;
+ virtual ~ChecksumRecordCorruptedException() {};
+
+ ChecksumRecordCorruptedException(const std::string &line) : RecordCorruptedException(line) {
+ setMessage(subtype());
+ }
+
+ ChecksumRecordCorruptedException withLineNumber(const size_t &lineNumber) const {
+ ChecksumRecordCorruptedException copy(*this);
+ copy.m_lineNumber = lineNumber;
+ copy.setMessage(copy.subtype());
+ return copy;
+ }
+
+private:
+ const std::string &subtype(void) {
+ static const std::string subtype("Checksum");
+ return subtype;
+ }
+};
+
+} /* namespace Cynara */
+
+#endif /* SRC_COMMON_EXCEPTIONS_CHECKSUMRECORDCORRUPTEDEXCEPTION_H_ */
diff --git a/src/common/exceptions/RecordCorruptedException.h b/src/common/exceptions/RecordCorruptedException.h
new file mode 100644
index 0000000..6177aab
--- /dev/null
+++ b/src/common/exceptions/RecordCorruptedException.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file src/common/exceptions/RecordCorruptedException.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Implementation of RecordCorruptedException
+ */
+
+#ifndef SRC_COMMON_EXCEPTIONS_RECORDCORRUPTEDEXCEPTION_H_
+#define SRC_COMMON_EXCEPTIONS_RECORDCORRUPTEDEXCEPTION_H_
+
+#include
+
+#include
+
+namespace Cynara {
+
+class RecordCorruptedException : public DatabaseException {
+public:
+ RecordCorruptedException(void) = delete;
+ virtual ~RecordCorruptedException() {};
+
+ RecordCorruptedException(const std::string &line)
+ : m_lineNumber(0), m_line(line), m_filename(std::string()) {
+ setMessage(std::string());
+ }
+
+ const std::string &message(void) const {
+ return m_message;
+ }
+
+ const std::string &filename(void) const {
+ return m_filename;
+ }
+
+ const std::string &line(void) const {
+ return m_line;
+ }
+
+ size_t lineNumber(void) const {
+ return m_lineNumber;
+ }
+
+protected:
+ std::string slicedLine(void) const {
+ return m_line.substr(0, 50) + (m_line.size() > 50 ? "..." : "");
+ }
+
+ std::string formattedMetadata(void) const {
+ return (m_filename.empty() ? "line" : m_filename)
+ + (m_lineNumber <= 0 ? "" : formattedLineNumber());
+ }
+
+ std::string formattedLineNumber(void) const {
+ return (m_filename.empty() ? " " : ":")
+ + std::to_string(static_cast(m_lineNumber));
+ }
+
+ void setMessage(const std::string &subtype) {
+ m_message = (subtype.empty() ? "Record" : subtype + " record") + " corrupted at "
+ + formattedMetadata() + ": <" + slicedLine() + ">";
+ }
+
+ size_t m_lineNumber;
+ std::string m_line;
+ std::string m_filename;
+ std::string m_message;
+};
+
+} /* namespace Cynara */
+
+#endif /* SRC_COMMON_EXCEPTIONS_RECORDCORRUPTEDEXCEPTION_H_ */
--
2.7.4
From 8a9adaa9c38a3269942181abadb5f700b7661ccb Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Thu, 26 Feb 2015 14:39:39 +0100
Subject: [PATCH 09/16] Fix basename() usage in ChecksumGenerator
Contents of a string passed to basename() as an argument may be modified
(it depends on implementation). In order not to perform unexpected
changes, duplicate of given string is passed to basename().
Change-Id: Ib783629160f9528a6054dd0f78b9ebd5e6870fb6
---
src/chsgen/ChecksumGenerator.cpp | 32 +++++++++++++++++++++++---------
src/chsgen/ChecksumGenerator.h | 4 ++--
2 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/src/chsgen/ChecksumGenerator.cpp b/src/chsgen/ChecksumGenerator.cpp
index 6255403..fcc76dc 100644
--- a/src/chsgen/ChecksumGenerator.cpp
+++ b/src/chsgen/ChecksumGenerator.cpp
@@ -23,6 +23,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -43,8 +45,10 @@ const char ChecksumGenerator::m_fieldSeparator(StorageConfig::fieldSeparator);
const char ChecksumGenerator::m_recordSeparator(StorageConfig::recordSeparator);
const std::string ChecksumGenerator::m_backupFilenameSuffix(StorageConfig::backupFilenameSuffix);
-ChecksumGenerator::ChecksumGenerator(int argc, char * const *argv) : m_copyStream(std::string()) {
- m_filename = (1 < argc ? argv[1] : std::string());
+ChecksumGenerator::ChecksumGenerator(int argc, char * const *argv) {
+ if (argc > 1) {
+ m_pathname = argv[1];
+ }
}
int ChecksumGenerator::run(void) {
@@ -65,11 +69,14 @@ int ChecksumGenerator::run(void) {
} catch (const std::length_error &ex) {
std::cerr << ex.what() << std::endl;
return CYNARA_API_UNKNOWN_ERROR;
+ } catch (const std::bad_alloc &ex) {
+ std::cerr << ex.what() << std::endl;
+ return CYNARA_API_OUT_OF_MEMORY;
}
}
const std::string ChecksumGenerator::generate(const std::string &data) {
- auto checksum = crypt(data.c_str(), "$1$");
+ const char *checksum = crypt(data.c_str(), "$1$");
if (nullptr != checksum) {
return std::string(checksum);
@@ -85,10 +92,10 @@ const std::string ChecksumGenerator::generate(const std::string &data) {
};
void ChecksumGenerator::openFileStream(void) {
- m_inputStream.open(m_filename);
+ m_inputStream.open(m_pathname);
if (!m_inputStream.is_open()) {
- throw FileNotFoundException(m_filename);
+ throw FileNotFoundException(m_pathname);
}
}
@@ -100,14 +107,21 @@ void ChecksumGenerator::copyFileStream(void) {
}
void ChecksumGenerator::printRecord(void) const {
- std::string filename(basename(m_filename.c_str()));
- getBasicFilename(filename);
+ std::unique_ptr pathnameDuplicate(strdup(m_pathname.c_str()), free);
+ if (pathnameDuplicate == nullptr) {
+ LOGE("Insufficient memory available to allocate duplicate filename: <%s>",
+ m_pathname.c_str());
+ throw std::bad_alloc();
+ }
+
+ std::string basename(::basename(pathnameDuplicate.get()));
+ removeBackupSuffix(basename);
- std::cout << filename << m_fieldSeparator << generate(m_copyStream.str())
+ std::cout << basename << m_fieldSeparator << generate(m_copyStream.str())
<< m_recordSeparator;
}
-void ChecksumGenerator::getBasicFilename(std::string &filename) const {
+void ChecksumGenerator::removeBackupSuffix(std::string &filename) const {
auto backupSuffixPos = filename.rfind(m_backupFilenameSuffix);
if (std::string::npos != backupSuffixPos &&
diff --git a/src/chsgen/ChecksumGenerator.h b/src/chsgen/ChecksumGenerator.h
index a3e96e0..30e34fb 100644
--- a/src/chsgen/ChecksumGenerator.h
+++ b/src/chsgen/ChecksumGenerator.h
@@ -42,11 +42,11 @@ private:
void openFileStream(void);
void copyFileStream(void);
void printRecord(void) const;
- void getBasicFilename(std::string &filename) const;
+ void removeBackupSuffix(std::string &filename) const;
std::ifstream m_inputStream;
std::stringstream m_copyStream;
- std::string m_filename;
+ std::string m_pathname;
static const char m_fieldSeparator;
static const char m_recordSeparator;
static const std::string m_backupFilenameSuffix;
--
2.7.4
From 7832866a7fbf8b6425e180d1dbdfe7b80ab8f96d Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Tue, 23 Dec 2014 14:53:59 +0100
Subject: [PATCH 10/16] Introduce ChecksumValidator
ChecksumValidator computes checksums for every file listed in checksum
index equivalent using crypt(3). As a result, base64-like (custom
alphabet) encoded strings are produced and compared with last known
corresponding digest. Its 4-character prefix indicates used algorithm.
Class will be later used as an integrity mechanism extension.
Change-Id: Ibaba636bae30c747e8eac5561e9b130d4398518e
---
src/storage/CMakeLists.txt | 2 +
src/storage/ChecksumValidator.cpp | 142 ++++++++++++++++++++++++++++++++++++++
src/storage/ChecksumValidator.h | 65 +++++++++++++++++
test/CMakeLists.txt | 1 +
4 files changed, 210 insertions(+)
create mode 100644 src/storage/ChecksumValidator.cpp
create mode 100644 src/storage/ChecksumValidator.h
diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt
index 7bccc8c..996b37a 100644
--- a/src/storage/CMakeLists.txt
+++ b/src/storage/CMakeLists.txt
@@ -24,6 +24,7 @@ SET(CYNARA_LIB_CYNARA_STORAGE_PATH ${CYNARA_PATH}/storage)
SET(LIB_CYNARA_STORAGE_SOURCES
${CYNARA_LIB_CYNARA_STORAGE_PATH}/BucketDeserializer.cpp
+ ${CYNARA_LIB_CYNARA_STORAGE_PATH}/ChecksumValidator.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/InMemoryStorageBackend.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/Integrity.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/Storage.cpp
@@ -51,6 +52,7 @@ SET_TARGET_PROPERTIES(
TARGET_LINK_LIBRARIES(${TARGET_LIB_CYNARA_STORAGE}
${CYNARA_DEP_LIBRARIES}
${TARGET_CYNARA_COMMON}
+ crypt
)
INSTALL(TARGETS ${TARGET_LIB_CYNARA_STORAGE} DESTINATION ${LIB_INSTALL_DIR})
diff --git a/src/storage/ChecksumValidator.cpp b/src/storage/ChecksumValidator.cpp
new file mode 100644
index 0000000..1354ad1
--- /dev/null
+++ b/src/storage/ChecksumValidator.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/storage/ChecksumValidator.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief This file contains ChecksumValidator implementation.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "ChecksumValidator.h"
+
+namespace Cynara {
+
+const std::string ChecksumValidator::m_checksumFilename(PathConfig::StoragePath::checksumFilename);
+const std::string ChecksumValidator::m_backupFilenameSuffix(
+ PathConfig::StoragePath::backupFilenameSuffix);
+
+void ChecksumValidator::load(std::istream &stream) {
+ m_sums.clear();
+
+ std::string line;
+ std::size_t lineNum = 1;
+ while (std::getline(stream, line, PathConfig::StoragePath::recordSeparator)) {
+ try {
+ std::size_t beginToken = 0;
+ std::string filename = parseFilename(line, beginToken);
+ std::string checksum = parseChecksum(line, beginToken);
+
+ m_sums.insert({ filename, checksum });
+ ++lineNum;
+ } catch (const ChecksumRecordCorruptedException &ex) {
+ throw ex.withLineNumber(lineNum);
+ }
+ }
+};
+
+const std::string ChecksumValidator::generate(const std::string &data) {
+ const char *checksum = crypt(data.c_str(), "$1$");
+
+ if (nullptr != checksum) {
+ return checksum;
+ }
+
+ int err = errno;
+ if (err == ENOSYS) {
+ LOGE("'crypt' function was not implemented; error [%d] : <%s>", err, strerror(err));
+ } else {
+ LOGE("'crypt' function error [%d] : <%s>", err, strerror(err));
+ }
+ throw UnexpectedErrorException(err, strerror(err));
+};
+
+void ChecksumValidator::compare(std::istream &stream, const std::string &pathname,
+ bool isBackupValid) {
+ if (isChecksumIndex(pathname)) {
+ return;
+ }
+
+ std::unique_ptr pathnameDuplicate(strdup(pathname.c_str()), free);
+ if (pathnameDuplicate == nullptr) {
+ LOGE("Insufficient memory available to allocate duplicate filename: <%s>",
+ pathname.c_str());
+ throw std::bad_alloc();
+ }
+
+ std::string filename(::basename(pathnameDuplicate.get()));
+ std::stringstream copyStream;
+
+ if (isBackupValid) {
+ auto backupSuffixPos = filename.rfind(m_backupFilenameSuffix);
+
+ if ((std::string::npos != backupSuffixPos) &&
+ (filename.size() == (backupSuffixPos + m_backupFilenameSuffix.size()))) {
+ filename.erase(backupSuffixPos);
+ }
+ }
+
+ std::copy(std::istreambuf_iterator(stream),
+ std::istreambuf_iterator(),
+ std::ostreambuf_iterator(copyStream));
+ stream.seekg(0);
+
+ if (m_sums[filename] != generate(copyStream.str())) {
+ throw ChecksumRecordCorruptedException(m_sums[filename]);
+ }
+};
+
+const std::string ChecksumValidator::parseFilename(const std::string &line,
+ std::size_t &beginToken) {
+ std::size_t filenameEndToken = line.find(PathConfig::StoragePath::fieldSeparator, beginToken);
+ if (filenameEndToken != beginToken && filenameEndToken != std::string::npos) {
+ auto filename = line.substr(beginToken, filenameEndToken - beginToken);
+ beginToken = filenameEndToken + 1;
+ return filename;
+ }
+ throw ChecksumRecordCorruptedException(line);
+}
+
+const std::string ChecksumValidator::parseChecksum(const std::string &line,
+ std::size_t &beginToken) {
+ if (beginToken >= line.size()) {
+ throw ChecksumRecordCorruptedException(line);
+ }
+
+ auto checksum = line.substr(beginToken);
+ beginToken = line.size();
+ return checksum;
+}
+
+bool ChecksumValidator::isChecksumIndex(const std::string &filename) const {
+ auto checksum = m_dbPath + m_checksumFilename;
+ return (filename == checksum || filename == checksum + m_backupFilenameSuffix);
+}
+
+} // namespace Cynara
diff --git a/src/storage/ChecksumValidator.h b/src/storage/ChecksumValidator.h
new file mode 100644
index 0000000..bfd577b
--- /dev/null
+++ b/src/storage/ChecksumValidator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/storage/ChecksumValidator.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief This file contains ChecksumValidator header.
+ */
+
+#ifndef SRC_STORAGE_CHECKSUMVALIDATOR_H_
+#define SRC_STORAGE_CHECKSUMVALIDATOR_H_
+
+#include
+#include
+#include
+#include
+
+namespace Cynara {
+
+class ChecksumValidator;
+typedef std::unique_ptr ChecksumValidatorUniquePtr;
+
+class ChecksumValidator {
+public:
+ ChecksumValidator(const std::string &path) : m_dbPath(path) {}
+
+ void load(std::istream &stream);
+ void compare(std::istream &stream, const std::string &pathname, bool isBackupValid);
+
+ void clear(void) {
+ m_sums.clear();
+ }
+
+ static const std::string generate(const std::string &data);
+
+protected:
+ typedef std::unordered_map Checksums;
+
+ bool isChecksumIndex(const std::string &pathname) const;
+
+ static const std::string parseFilename(const std::string &line, std::size_t &beginToken);
+ static const std::string parseChecksum(const std::string &line, std::size_t &beginToken);
+
+ Checksums m_sums;
+ const std::string m_dbPath;
+ static const std::string m_checksumFilename;
+ static const std::string m_backupFilenameSuffix;
+};
+
+} // namespace Cynara
+
+#endif // SRC_STORAGE_CHECKSUMVALIDATOR_H_
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d937d3c..f9b42a8 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -63,6 +63,7 @@ SET(CYNARA_SOURCES_FOR_TESTS
${CYNARA_SRC}/helpers/creds-commons/creds-commons.cpp
${CYNARA_SRC}/service/main/CmdlineParser.cpp
${CYNARA_SRC}/storage/BucketDeserializer.cpp
+ ${CYNARA_SRC}/storage/ChecksumValidator.cpp
${CYNARA_SRC}/storage/InMemoryStorageBackend.cpp
${CYNARA_SRC}/storage/Integrity.cpp
${CYNARA_SRC}/storage/Storage.cpp
--
2.7.4
From 9f0e503b603acb3bcb7dfedd6fd27216070e6be7 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Tue, 27 Jan 2015 11:47:19 +0100
Subject: [PATCH 11/16] Add tests for ChecksumValidator
Add tests checking if ChecksumValidator properly:
* generates checksums,
* loads them or rejects corrupted records,
* supports backup files.
Change-Id: I2e4222283cc0676490134819561824df6661034f
---
test/CMakeLists.txt | 1 +
test/storage/checksum/checksumvalidator.cpp | 154 +++++++++++++++++++++++
test/storage/checksum/checksumvalidatorfixture.h | 54 ++++++++
test/storage/checksum/fakechecksumvalidator.h | 37 ++++++
4 files changed, 246 insertions(+)
create mode 100644 test/storage/checksum/checksumvalidator.cpp
create mode 100644 test/storage/checksum/checksumvalidatorfixture.h
create mode 100644 test/storage/checksum/fakechecksumvalidator.h
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index f9b42a8..5050634 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -92,6 +92,7 @@ SET(CYNARA_TESTS_SOURCES
cyad/policy_parser.cpp
helpers.cpp
service/main/cmdlineparser.cpp
+ storage/checksum/checksumvalidator.cpp
storage/performance/bucket.cpp
storage/storage/policies.cpp
storage/storage/check.cpp
diff --git a/test/storage/checksum/checksumvalidator.cpp b/test/storage/checksum/checksumvalidator.cpp
new file mode 100644
index 0000000..19918f3
--- /dev/null
+++ b/test/storage/checksum/checksumvalidator.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file test/storage/checksum/checksumvalidator.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Tests of ChecksumValidator
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "checksumvalidatorfixture.h"
+#include "fakechecksumvalidator.h"
+
+using namespace Cynara;
+
+const std::string ChecksumValidatorFixture::m_dbPath("/fake/path/");
+const std::string ChecksumValidatorFixture::m_filename("fakeFilename");
+const std::string ChecksumValidatorFixture::m_checksum("$1$$fakeChecksum");
+const std::string ChecksumValidatorFixture::m_backupFilenameSuffix(
+ PathConfig::StoragePath::backupFilenameSuffix);
+const char ChecksumValidatorFixture::m_fieldSeparator(PathConfig::StoragePath::fieldSeparator);
+const char ChecksumValidatorFixture::m_recordSeparator(PathConfig::StoragePath::recordSeparator);
+const size_t ChecksumValidatorFixture::m_firstLine(1);
+
+/**
+ * @brief Verify if generate() can use systems' crypt(3) implementation
+ * @test Expected result: no exceptions are thrown and non-empty string is returned
+ */
+TEST_F(ChecksumValidatorFixture, generateChecksum) {
+ for (const auto &data : { std::string("test-data"), std::string() }) {
+ SCOPED_TRACE(data);
+
+ std::string returnedChecksum;
+ ASSERT_NO_THROW(returnedChecksum = ChecksumValidator::generate(data));
+ ASSERT_NE(std::string(), returnedChecksum);
+ }
+}
+
+/**
+ * @brief Verify if load() can successfully parse sample checksum record
+ * @test Expected result:
+ * - no exceptions are thrown from load()
+ * - proper checksums are stored for corresponding files
+ */
+TEST_F(ChecksumValidatorFixture, parseCorrectRecords) {
+ std::istringstream checksums(m_filename + m_fieldSeparator + m_checksum);
+
+ FakeChecksumValidator validator(m_dbPath);
+ ASSERT_NO_THROW(validator.load(checksums));
+ ASSERT_EQ(m_checksum, validator.sums().at(m_filename));
+}
+
+/**
+ * @brief Verify if load() rejects storing corrupted checksum records
+ * @test Expected result:
+ * - load() throws ChecksumRecordCorruptedException
+ * - no data is stored (there was no correct data to insert)
+ */
+TEST_F(ChecksumValidatorFixture, parseCorruptedRecords) {
+ const auto badLines = { m_filename + m_fieldSeparator,
+ m_filename + m_checksum,
+ m_fieldSeparator + m_checksum };
+
+ FakeChecksumValidator validator(m_dbPath);
+
+ for (const auto &badLine : badLines) {
+ SCOPED_TRACE(badLine);
+ std::istringstream checksums(badLine);
+
+ ASSERT_THROW(validator.load(checksums), ChecksumRecordCorruptedException);
+ ASSERT_TRUE(validator.sums().empty());
+ }
+}
+
+/**
+ * @brief Verify if compare() can successfully check sample database file
+ * @test Expected result: no exceptions are thrown and file contents are still readable
+ */
+TEST_F(ChecksumValidatorFixture, compareBasicAndBackup) {
+ FakeChecksumValidator validator(m_dbPath);
+ std::string checksumsContents;
+ simpleChecksumsContents(checksumsContents);
+
+ std::istringstream checksums(checksumsContents);
+ validator.load(checksums);
+
+ std::unordered_map files = { { "_", std::string() },
+ { "buckets", ";0x0;\n" } };
+
+ for (const auto &file : files) {
+ const auto filename = m_dbPath + file.first;
+ const auto contents = file.second;
+ std::istringstream fakeFile(contents);
+
+ SCOPED_TRACE(filename);
+
+ ASSERT_NO_THROW(validator.compare(fakeFile, filename, false));
+ ASSERT_NO_THROW(validator.compare(fakeFile, filename + m_backupFilenameSuffix, true));
+
+ ASSERT_EQ(contents, fakeFile.str());
+ }
+}
+
+/**
+ * @brief Verify if compare() throws an exception when checksum mismatch is detected
+ * @test Expected result: ChecksumRecordCorruptedException is thrown
+ */
+TEST_F(ChecksumValidatorFixture, checksumMismatch) {
+ FakeChecksumValidator validator(m_dbPath);
+ std::string checksumsContents;
+ simpleChecksumsContents(checksumsContents);
+
+ std::istringstream checksums(checksumsContents);
+ validator.load(checksums);
+
+ // Please note that default policy is set to ALLOW instead of DENY
+ std::unordered_map files = { { "_", "client;user;privilege;0x0;" },
+ { "buckets", ";0xFFFF;\n" } };
+
+ for (const auto &file : files) {
+ const auto filename = m_dbPath + file.first;
+ const auto contents = file.second;
+ std::istringstream fakeFile(contents);
+ SCOPED_TRACE(filename);
+
+ ASSERT_THROW(validator.compare(fakeFile, filename, false),
+ ChecksumRecordCorruptedException);
+ }
+}
diff --git a/test/storage/checksum/checksumvalidatorfixture.h b/test/storage/checksum/checksumvalidatorfixture.h
new file mode 100644
index 0000000..6fb28f6
--- /dev/null
+++ b/test/storage/checksum/checksumvalidatorfixture.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file test/storage/checksum/checksumvalidatorfixture.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Fixture for ChecksumValidator tests
+ */
+
+#ifndef CHECKSUMVALIDATORFIXTURE_H_
+#define CHECKSUMVALIDATORFIXTURE_H_
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+class ChecksumValidatorFixture : public ::testing::Test {
+protected:
+ void simpleChecksumsContents(std::string &contents) {
+ std::stringstream buffer;
+ buffer << "_" << m_fieldSeparator << "$1$$qRPK7m23GJusamGpoGLby/" << m_recordSeparator
+ << "buckets" << m_fieldSeparator << "$1$$6ZlVs5lw2nZgVmiw0BdY21"
+ << m_recordSeparator;
+
+ contents = buffer.str();
+ }
+
+ static const std::string m_dbPath;
+ static const std::string m_filename;
+ static const std::string m_checksum;
+ static const std::string m_backupFilenameSuffix;
+ static const char m_fieldSeparator;
+ static const char m_recordSeparator;
+ static const size_t m_firstLine;
+};
+
+#endif /* CHECKSUMVALIDATORFIXTURE_H_ */
diff --git a/test/storage/checksum/fakechecksumvalidator.h b/test/storage/checksum/fakechecksumvalidator.h
new file mode 100644
index 0000000..af3ed82
--- /dev/null
+++ b/test/storage/checksum/fakechecksumvalidator.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file test/storage/checksum/fakechecksumvalidator.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief Mock of ChecksumValidator
+ */
+
+#ifndef FAKECHECKSUMVALIDATOR_H_
+#define FAKECHECKSUMVALIDATOR_H_
+
+#include
+
+class FakeChecksumValidator : public Cynara::ChecksumValidator {
+public:
+ using Cynara::ChecksumValidator::ChecksumValidator;
+
+ const Checksums &sums(void) {
+ return m_sums;
+ }
+};
+
+#endif /* FAKECHECKSUMVALIDATOR_H_ */
--
2.7.4
From 58d92c8f005be204b6d0cb990d8276aed1f3b76a Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Mon, 12 Jan 2015 15:01:54 +0100
Subject: [PATCH 12/16] Make StorageSerializer a template class
This patch modifies StorageSerializer so that it will be able to use
other streams than std::ostream and its derivatives. Within current
class hierarchy custom output streams with overloaded insertion operator
(operator<<) cannot be used, as it is non-virtual in std::ostream.
Change-Id: I3e713329c55aacfbb8daa23a5c4579d4c5db9f52
---
src/storage/CMakeLists.txt | 3 +-
src/storage/InMemoryStorageBackend.cpp | 6 +--
src/storage/InMemoryStorageBackend.h | 3 +-
src/storage/StorageSerializer.cpp | 92 ----------------------------------
src/storage/StorageSerializer.h | 68 ++++++++++++++++++++++++-
test/CMakeLists.txt | 1 -
test/storage/serializer/dump.cpp | 8 +--
test/storage/serializer/dump_load.cpp | 4 +-
test/storage/serializer/serialize.cpp | 27 +++++-----
9 files changed, 93 insertions(+), 119 deletions(-)
delete mode 100644 src/storage/StorageSerializer.cpp
diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt
index 996b37a..72f0ec2 100644
--- a/src/storage/CMakeLists.txt
+++ b/src/storage/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+# Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -29,7 +29,6 @@ SET(LIB_CYNARA_STORAGE_SOURCES
${CYNARA_LIB_CYNARA_STORAGE_PATH}/Integrity.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/Storage.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/StorageDeserializer.cpp
- ${CYNARA_LIB_CYNARA_STORAGE_PATH}/StorageSerializer.cpp
)
INCLUDE_DIRECTORIES(
diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp
index a5e08b1..d6655e2 100644
--- a/src/storage/InMemoryStorageBackend.cpp
+++ b/src/storage/InMemoryStorageBackend.cpp
@@ -100,7 +100,7 @@ void InMemoryStorageBackend::save(void) {
std::string indexFilename = m_dbPath + m_indexFilename;
openDumpFileStream(indexStream, indexFilename + m_backupFilenameSuffix);
- StorageSerializer storageSerializer(indexStream);
+ StorageSerializer storageSerializer(indexStream);
storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
this, std::placeholders::_1));
@@ -253,14 +253,14 @@ std::shared_ptr InMemoryStorageBackend::bucketStreamOpener(
}
}
-std::shared_ptr InMemoryStorageBackend::bucketDumpStreamOpener(
+std::shared_ptr > InMemoryStorageBackend::bucketDumpStreamOpener(
const PolicyBucketId &bucketId) {
std::string bucketFilename = m_dbPath + m_bucketFilenamePrefix +
bucketId + m_backupFilenameSuffix;
auto bucketStream = std::make_shared();
openDumpFileStream(bucketStream, bucketFilename);
- return std::make_shared(bucketStream);
+ return std::make_shared >(bucketStream);
}
void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) {
diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h
index c9e63c2..10251c7 100644
--- a/src/storage/InMemoryStorageBackend.h
+++ b/src/storage/InMemoryStorageBackend.h
@@ -71,7 +71,8 @@ protected:
virtual void openDumpFileStream(std::shared_ptr stream,
const std::string &filename);
- std::shared_ptr bucketDumpStreamOpener(const PolicyBucketId &bucketId);
+ std::shared_ptr > bucketDumpStreamOpener(
+ const PolicyBucketId &bucketId);
virtual void postLoadCleanup(bool isBackupValid);
diff --git a/src/storage/StorageSerializer.cpp b/src/storage/StorageSerializer.cpp
deleted file mode 100644
index 9f701dd..0000000
--- a/src/storage/StorageSerializer.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @file src/storage/StorageSerializer.cpp
- * @author Aleksander Zdyb
- * @version 1.0
- * @brief Implementation of Cynara::StorageSerializer methods
- */
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "StorageSerializer.h"
-
-namespace Cynara {
-
-StorageSerializer::StorageSerializer(std::shared_ptr os) : m_outStream(os) {
-}
-
-void StorageSerializer::dump(const Buckets &buckets,
- BucketStreamOpener streamOpener) {
-
- for (const auto bucketIter : buckets) {
- const auto &bucket = bucketIter.second;
-
- dumpFields(bucket.id(), bucket.defaultPolicy().policyType(),
- bucket.defaultPolicy().metadata());
- }
-
- for (const auto bucketIter : buckets) {
- const auto &bucketId = bucketIter.first;
- const auto &bucket = bucketIter.second;
- auto bucketSerializer = streamOpener(bucketId);
-
- if (bucketSerializer != nullptr) {
- bucketSerializer->dump(bucket);
- } else {
- throw BucketSerializationException(bucketId);
- }
- }
-}
-
-void StorageSerializer::dump(const PolicyBucket& bucket) {
- for (auto it = std::begin(bucket); it != std::end(bucket); ++it) {
- const auto &policy = *it;
- dump(policy);
- }
-}
-
-void StorageSerializer::dump(const PolicyKeyFeature &keyFeature) {
- *m_outStream << keyFeature.toString();
-}
-
-void StorageSerializer::dump(const PolicyType &policyType) {
- auto oldFormat = m_outStream->flags();
- *m_outStream << "0x" << std::uppercase << std::hex << policyType;
- m_outStream->flags(oldFormat);
-}
-
-void StorageSerializer::dump(const PolicyResult::PolicyMetadata &metadata) {
- *m_outStream << metadata;
-}
-
-void StorageSerializer::dump(const PolicyCollection::value_type &policy) {
- const auto &key = policy->key();
- const auto &result = policy->result();
-
- dumpFields(key.client(), key.user(), key.privilege(), result.policyType(), result.metadata());
-}
-
-} /* namespace Cynara */
diff --git a/src/storage/StorageSerializer.h b/src/storage/StorageSerializer.h
index 42982b2..40eb784 100644
--- a/src/storage/StorageSerializer.h
+++ b/src/storage/StorageSerializer.h
@@ -25,9 +25,13 @@
#include
#include
+#include
#include
+#include
#include
+#include
+#include
#include
#include
#include
@@ -39,13 +43,14 @@
namespace Cynara {
+template
class StorageSerializer {
public:
typedef std::function(const PolicyBucketId &)>
BucketStreamOpener;
- StorageSerializer(std::shared_ptr os);
+ StorageSerializer(std::shared_ptr os);
virtual ~StorageSerializer() {};
virtual void dump(const Buckets &buckets,
@@ -72,9 +77,68 @@ protected:
void dump(const PolicyCollection::value_type &policy);
private:
- std::shared_ptr m_outStream;
+ std::shared_ptr m_outStream;
};
+template
+StorageSerializer::StorageSerializer(std::shared_ptr os) : m_outStream(os) {
+}
+
+template
+void StorageSerializer::dump(const Buckets &buckets, BucketStreamOpener streamOpener) {
+ for (const auto bucketIter : buckets) {
+ const auto &bucket = bucketIter.second;
+
+ dumpFields(bucket.id(), bucket.defaultPolicy().policyType(),
+ bucket.defaultPolicy().metadata());
+ }
+
+ for (const auto bucketIter : buckets) {
+ const auto &bucketId = bucketIter.first;
+ const auto &bucket = bucketIter.second;
+ auto bucketSerializer = streamOpener(bucketId);
+
+ if (bucketSerializer != nullptr) {
+ bucketSerializer->dump(bucket);
+ } else {
+ throw BucketSerializationException(bucketId);
+ }
+ }
+}
+
+template
+void StorageSerializer::dump(const PolicyBucket &bucket) {
+ for (auto it = std::begin(bucket); it != std::end(bucket); ++it) {
+ const auto &policy = *it;
+ dump(policy);
+ }
+}
+
+template
+void StorageSerializer::dump(const PolicyKeyFeature &keyFeature) {
+ *m_outStream << keyFeature.toString();
+}
+
+template
+void StorageSerializer::dump(const PolicyType &policyType) {
+ auto oldFormat = m_outStream->flags();
+ *m_outStream << "0x" << std::uppercase << std::hex << policyType;
+ m_outStream->flags(oldFormat);
+}
+
+template
+void StorageSerializer::dump(const PolicyResult::PolicyMetadata &metadata) {
+ *m_outStream << metadata;
+}
+
+template
+void StorageSerializer::dump(const PolicyCollection::value_type &policy) {
+ const auto &key = policy->key();
+ const auto &result = policy->result();
+
+ dumpFields(key.client(), key.user(), key.privilege(), result.policyType(), result.metadata());
+}
+
} /* namespace Cynara */
#endif /* SRC_STORAGE_STORAGESERIALIZER_H_ */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 5050634..9cf89d7 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -68,7 +68,6 @@ SET(CYNARA_SOURCES_FOR_TESTS
${CYNARA_SRC}/storage/Integrity.cpp
${CYNARA_SRC}/storage/Storage.cpp
${CYNARA_SRC}/storage/StorageDeserializer.cpp
- ${CYNARA_SRC}/storage/StorageSerializer.cpp
)
SET(CYNARA_TESTS_SOURCES
diff --git a/test/storage/serializer/dump.cpp b/test/storage/serializer/dump.cpp
index 2eafcf7..1daaf32 100644
--- a/test/storage/serializer/dump.cpp
+++ b/test/storage/serializer/dump.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ TEST(serializer_dump, dump_empty_bucket) {
auto oss = std::make_shared();
PolicyBucket bucket("empty");
- StorageSerializer serializer(oss);
+ StorageSerializer serializer(oss);
serializer.dump(bucket);
ASSERT_EQ("", oss->str());
@@ -69,7 +69,7 @@ TEST(serializer_dump, dump_bucket) {
Policy::simpleWithKey(pk2, DENY) }));
auto outStream = std::make_shared();
- StorageSerializer serializer(outStream);
+ StorageSerializer serializer(outStream);
serializer.dump(bucket);
// Split stream into records
@@ -99,7 +99,7 @@ TEST(serializer_dump, dump_bucket_bucket) {
Policy::bucketWithKey(pk3, bucketId) }};
auto outStream = std::make_shared();
- StorageSerializer serializer(outStream);
+ StorageSerializer serializer(outStream);
serializer.dump(bucket);
// Split stream into records
diff --git a/test/storage/serializer/dump_load.cpp b/test/storage/serializer/dump_load.cpp
index f3eff9b..cd4ce5c 100644
--- a/test/storage/serializer/dump_load.cpp
+++ b/test/storage/serializer/dump_load.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ TEST(dump_load, bucket) {
auto ioStream = std::make_shared();
- StorageSerializer serializer(ioStream);
+ StorageSerializer serializer(ioStream);
serializer.dump(bucket);
BucketDeserializer deserializer(ioStream);
diff --git a/test/storage/serializer/serialize.cpp b/test/storage/serializer/serialize.cpp
index 938283d..1681a5b 100644
--- a/test/storage/serializer/serialize.cpp
+++ b/test/storage/serializer/serialize.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,21 +37,24 @@
class FakeStreamForBucketId {
public:
+ typedef std::shared_ptr >
+ StringstreamStorageSerializerPtr;
+
MOCK_METHOD1(streamForBucketId,
- std::shared_ptr(const Cynara::PolicyBucketId &));
+ StringstreamStorageSerializerPtr(const Cynara::PolicyBucketId &));
- Cynara::StorageSerializer::BucketStreamOpener streamOpener() {
+ Cynara::StorageSerializer::BucketStreamOpener streamOpener() {
return std::bind(&FakeStreamForBucketId::streamForBucketId, this, std::placeholders::_1);
}
};
// Fake StorageSerializer for Cynara::PolicyBucket
-class FakeStorageSerializer : public Cynara::StorageSerializer {
+class FakeStorageSerializer : public Cynara::StorageSerializer {
public:
- FakeStorageSerializer(std::shared_ptr o) : Cynara::StorageSerializer(o),
- outStream(o) {}
+ FakeStorageSerializer(std::shared_ptr o)
+ : Cynara::StorageSerializer(o), outStream(o) {}
MOCK_METHOD1(dump, void(const Cynara::PolicyBucket &bucket));
- std::shared_ptr outStream;
+ std::shared_ptr outStream;
};
class StorageSerializerFixture : public ::testing::Test {
@@ -67,8 +70,8 @@ using namespace Cynara;
// Be sure no calls to streamForBucketId() are made
// and output stream is not touched
TEST_F(StorageSerializerFixture, dump_buckets_empty) {
- auto outStream = std::make_shared();
- StorageSerializer serializer(outStream);
+ auto outStream = std::make_shared();
+ StorageSerializer serializer(outStream);
serializer.dump(Buckets(), fakeStreamOpener.streamOpener());
// Stream should be empty
@@ -83,7 +86,7 @@ TEST_F(StorageSerializerFixture, dump_buckets) {
// Will be returned as serializer for buckets
auto fakeBucketSerializer = std::make_shared(
- std::make_shared());
+ std::make_shared());
buckets = {
{ "bucket1", PolicyBucket("bucket1", PredefinedPolicyType::DENY) },
@@ -93,7 +96,7 @@ TEST_F(StorageSerializerFixture, dump_buckets) {
};
auto outStream = std::make_shared();
- StorageSerializer dbSerializer(outStream);
+ StorageSerializer dbSerializer(outStream);
// Make sure stream was opened for each bucket
EXPECT_CALL(fakeStreamOpener, streamForBucketId(_))
@@ -128,7 +131,7 @@ TEST_F(StorageSerializerFixture, dump_buckets_io_error) {
};
auto outStream = std::make_shared();
- StorageSerializer dbSerializer(outStream);
+ StorageSerializer dbSerializer(outStream);
// Make sure stream was opened for each bucket
EXPECT_CALL(fakeStreamOpener, streamForBucketId(_))
--
2.7.4
From bf8b0794dbe4d401430cae787e6bc3e6e0d09224 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Thu, 15 Jan 2015 08:19:15 +0100
Subject: [PATCH 13/16] Introduce ChecksumStream
ChecksumStream will replace std::ofstream for saving database contents
in storage. This way data will be not only written to the files, but
also its checksums will be computed and stored in given stream (database
index equivalent for storing checksums).
Checksum computing is performed during stream destruction in order to be
sure that all necessary data was already collected.
Change-Id: I4a9ff2e29361f337cacd790d77364feca854a706
---
src/storage/CMakeLists.txt | 1 +
src/storage/ChecksumStream.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++
src/storage/ChecksumStream.h | 70 +++++++++++++++++++++++++++++++++++++++++
test/CMakeLists.txt | 1 +
4 files changed, 143 insertions(+)
create mode 100644 src/storage/ChecksumStream.cpp
create mode 100644 src/storage/ChecksumStream.h
diff --git a/src/storage/CMakeLists.txt b/src/storage/CMakeLists.txt
index 72f0ec2..f75bc06 100644
--- a/src/storage/CMakeLists.txt
+++ b/src/storage/CMakeLists.txt
@@ -24,6 +24,7 @@ SET(CYNARA_LIB_CYNARA_STORAGE_PATH ${CYNARA_PATH}/storage)
SET(LIB_CYNARA_STORAGE_SOURCES
${CYNARA_LIB_CYNARA_STORAGE_PATH}/BucketDeserializer.cpp
+ ${CYNARA_LIB_CYNARA_STORAGE_PATH}/ChecksumStream.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/ChecksumValidator.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/InMemoryStorageBackend.cpp
${CYNARA_LIB_CYNARA_STORAGE_PATH}/Integrity.cpp
diff --git a/src/storage/ChecksumStream.cpp b/src/storage/ChecksumStream.cpp
new file mode 100644
index 0000000..551307e
--- /dev/null
+++ b/src/storage/ChecksumStream.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/storage/ChecksumStream.cpp
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief This file contains ChecksumStream implementation.
+ */
+
+#include
+#include
+
+#include
+
+#include
+
+#include "ChecksumStream.h"
+
+namespace Cynara {
+
+const char ChecksumStream::m_fieldSeparator(PathConfig::StoragePath::fieldSeparator);
+const char ChecksumStream::m_recordSeparator(PathConfig::StoragePath::recordSeparator);
+
+ChecksumStream::~ChecksumStream() {
+ if (!std::uncaught_exception()) {
+ save();
+ }
+}
+
+ChecksumStream& ChecksumStream::operator<<(std::ostream& (*manip)(std::ostream&)) {
+ m_bufStream << manip;
+ m_outStream << manip;
+ return *this;
+}
+
+void ChecksumStream::open(const std::string &filename, std::ios_base::openmode mode) {
+ m_outStream.open(filename, mode);
+}
+
+bool ChecksumStream::is_open(void) const {
+ return m_outStream.is_open();
+}
+
+std::ios_base::fmtflags ChecksumStream::flags(void) const {
+ return m_outStream.flags();
+}
+
+std::ios_base::fmtflags ChecksumStream::flags(std::ios_base::fmtflags flags) {
+ return m_outStream.flags(flags);
+}
+
+void ChecksumStream::save() {
+ m_outStream.close();
+ *m_chsStream << m_filename << m_fieldSeparator << ChecksumValidator::generate(m_bufStream.str())
+ << m_recordSeparator;
+}
+
+} // namespace Cynara
diff --git a/src/storage/ChecksumStream.h b/src/storage/ChecksumStream.h
new file mode 100644
index 0000000..ddc6e6f
--- /dev/null
+++ b/src/storage/ChecksumStream.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/**
+ * @file src/storage/ChecksumStream.h
+ * @author Pawel Wieczorek
+ * @version 1.0
+ * @brief This file contains ChecksumStream header.
+ */
+
+#ifndef SRC_STORAGE_CHECKSUMSTREAM_H_
+#define SRC_STORAGE_CHECKSUMSTREAM_H_
+
+#include
+#include
+#include
+#include
+#include
+
+namespace Cynara {
+
+class ChecksumStream {
+public:
+ ChecksumStream(const std::string &filename, const std::shared_ptr &stream)
+ : m_chsStream(stream), m_filename(filename) {
+ }
+ ~ChecksumStream();
+
+ template
+ ChecksumStream& operator<<(const Type &item);
+ ChecksumStream& operator<<(std::ostream& (*manip)(std::ostream&));
+
+ void open(const std::string &filename, std::ios_base::openmode mode);
+ bool is_open(void) const;
+ std::ios_base::fmtflags flags(void) const;
+ std::ios_base::fmtflags flags(std::ios_base::fmtflags flags);
+
+private:
+ void save(void);
+
+ std::shared_ptr m_chsStream;
+ std::ofstream m_outStream;
+ std::stringstream m_bufStream;
+ const std::string m_filename;
+ static const char m_fieldSeparator;
+ static const char m_recordSeparator;
+};
+
+template
+ChecksumStream& ChecksumStream::operator<<(const Type& item) {
+ m_bufStream << item;
+ m_outStream << item;
+ return *this;
+}
+
+} // namespace Cynara
+
+#endif // SRC_STORAGE_CHECKSUMSTREAM_H_
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 9cf89d7..189268d 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -63,6 +63,7 @@ SET(CYNARA_SOURCES_FOR_TESTS
${CYNARA_SRC}/helpers/creds-commons/creds-commons.cpp
${CYNARA_SRC}/service/main/CmdlineParser.cpp
${CYNARA_SRC}/storage/BucketDeserializer.cpp
+ ${CYNARA_SRC}/storage/ChecksumStream.cpp
${CYNARA_SRC}/storage/ChecksumValidator.cpp
${CYNARA_SRC}/storage/InMemoryStorageBackend.cpp
${CYNARA_SRC}/storage/Integrity.cpp
--
2.7.4
From f08a80ee755ba5aed0450bb04eaa235e3966ab05 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Tue, 23 Dec 2014 17:18:16 +0100
Subject: [PATCH 14/16] Adjust InMemoryStorageBackend to ChecksumValidator
InMemoryStorageBackend uses ChecksumValidator as a checksum loader and
comparator. This patch also includes files needed by storage unit tests
to work properly.
Change-Id: I541975351275bd6a30e7cf627697c9657161312f
---
src/storage/InMemoryStorageBackend.cpp | 27 ++++++++++++++++++++-------
src/storage/InMemoryStorageBackend.h | 9 +++++++--
src/storage/Integrity.cpp | 8 +++++++-
test/db/db2/checksum | 1 +
test/db/db3/checksum | 2 ++
test/db/db4/checksum | 3 +++
test/db/db5/checksum | 3 +++
test/db/db6/checksum | 3 +++
test/db/db6/checksum~ | 3 +++
9 files changed, 49 insertions(+), 10 deletions(-)
create mode 100644 test/db/db2/checksum
create mode 100644 test/db/db3/checksum
create mode 100644 test/db/db4/checksum
create mode 100644 test/db/db5/checksum
create mode 100644 test/db/db6/checksum
create mode 100644 test/db/db6/checksum~
diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp
index d6655e2..249eccf 100644
--- a/src/storage/InMemoryStorageBackend.cpp
+++ b/src/storage/InMemoryStorageBackend.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -51,6 +52,7 @@
namespace Cynara {
+const std::string InMemoryStorageBackend::m_chsFilename(PathConfig::StoragePath::checksumFilename);
const std::string InMemoryStorageBackend::m_indexFilename(PathConfig::StoragePath::indexFilename);
const std::string InMemoryStorageBackend::m_backupFilenameSuffix(
PathConfig::StoragePath::backupFilenameSuffix);
@@ -58,26 +60,32 @@ const std::string InMemoryStorageBackend::m_bucketFilenamePrefix(
PathConfig::StoragePath::bucketFilenamePrefix);
InMemoryStorageBackend::InMemoryStorageBackend(const std::string &path) : m_dbPath(path),
- m_integrity(path) {
+ m_checksum(path), m_integrity(path) {
}
void InMemoryStorageBackend::load(void) {
bool isBackupValid = m_integrity.backupGuardExists();
std::string bucketSuffix = "";
std::string indexFilename = m_dbPath + m_indexFilename;
+ std::string chsFilename = m_dbPath + m_chsFilename;
if (isBackupValid) {
bucketSuffix += m_backupFilenameSuffix;
indexFilename += m_backupFilenameSuffix;
+ chsFilename += m_backupFilenameSuffix;
}
try {
+ auto chsStream = std::make_shared();
+ openFileStream(chsStream, chsFilename, isBackupValid);
+ m_checksum.load(*chsStream);
+
auto indexStream = std::make_shared();
- openFileStream(indexStream, indexFilename);
+ openFileStream(indexStream, indexFilename, isBackupValid);
StorageDeserializer storageDeserializer(indexStream,
std::bind(&InMemoryStorageBackend::bucketStreamOpener, this,
- std::placeholders::_1, bucketSuffix));
+ std::placeholders::_1, bucketSuffix, isBackupValid));
storageDeserializer.initBuckets(buckets());
storageDeserializer.loadBuckets(buckets());
@@ -86,6 +94,7 @@ void InMemoryStorageBackend::load(void) {
buckets().clear();
// TODO: Implement emergency mode toggle
}
+ m_checksum.clear();
if (!hasBucket(defaultPolicyBucketId)) {
LOGN("Creating defaultBucket.");
@@ -222,7 +231,7 @@ void InMemoryStorageBackend::erasePolicies(const PolicyBucketId &bucketId, bool
}
void InMemoryStorageBackend::openFileStream(std::shared_ptr stream,
- const std::string &filename) {
+ const std::string &filename, bool isBackupValid) {
// TODO: Consider adding exceptions to streams and handling them:
// stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
stream->open(filename);
@@ -230,6 +239,8 @@ void InMemoryStorageBackend::openFileStream(std::shared_ptr strea
if (!stream->is_open()) {
throw FileNotFoundException(filename);
}
+
+ m_checksum.compare(*stream, filename, isBackupValid);
}
void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr stream,
@@ -242,14 +253,16 @@ void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr s
}
std::shared_ptr InMemoryStorageBackend::bucketStreamOpener(
- const PolicyBucketId &bucketId, const std::string &filenameSuffix) {
+ const PolicyBucketId &bucketId, const std::string &filenameSuffix, bool isBackupValid) {
std::string bucketFilename = m_dbPath + m_bucketFilenamePrefix + bucketId + filenameSuffix;
auto bucketStream = std::make_shared();
try {
- openFileStream(bucketStream, bucketFilename);
+ openFileStream(bucketStream, bucketFilename, isBackupValid);
return std::make_shared(bucketStream);
} catch (const FileNotFoundException &) {
return nullptr;
+ } catch (const std::bad_alloc &) {
+ return nullptr;
}
}
@@ -269,7 +282,7 @@ void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) {
}
//in case there were unnecessary files in db directory
m_integrity.deleteNonIndexedFiles(std::bind(&InMemoryStorageBackend::hasBucket, this,
- std::placeholders::_1));
+ std::placeholders::_1));
}
} /* namespace Cynara */
diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h
index 10251c7..65af96b 100644
--- a/src/storage/InMemoryStorageBackend.h
+++ b/src/storage/InMemoryStorageBackend.h
@@ -35,6 +35,7 @@
#include
#include
+#include
#include
#include
#include
@@ -65,9 +66,11 @@ public:
const PolicyKey &filter);
protected:
- void openFileStream(std::shared_ptr stream, const std::string &filename);
+ void openFileStream(std::shared_ptr stream, const std::string &filename,
+ bool isBackupValid);
std::shared_ptr bucketStreamOpener(const PolicyBucketId &bucketId,
- const std::string &fileNameSuffix);
+ const std::string &fileNameSuffix,
+ bool isBackupValid);
virtual void openDumpFileStream(std::shared_ptr stream,
const std::string &filename);
@@ -79,7 +82,9 @@ protected:
private:
std::string m_dbPath;
Buckets m_buckets;
+ ChecksumValidator m_checksum;
Integrity m_integrity;
+ static const std::string m_chsFilename;
static const std::string m_indexFilename;
static const std::string m_backupFilenameSuffix;
static const std::string m_bucketFilenamePrefix;
diff --git a/src/storage/Integrity.cpp b/src/storage/Integrity.cpp
index 5dfa624..0b8e583 100644
--- a/src/storage/Integrity.cpp
+++ b/src/storage/Integrity.cpp
@@ -83,6 +83,7 @@ void Integrity::syncDatabase(const Buckets &buckets, bool syncBackup) {
}
syncElement(m_dbPath + m_indexFilename + suffix);
+ syncElement(m_dbPath + PathConfig::StoragePath::checksumFilename + suffix);
syncDirectory(m_dbPath);
}
@@ -152,7 +153,8 @@ void Integrity::syncElement(const std::string &filename, int flags, mode_t mode)
if (fileFd < 0) {
int err = errno;
if (err != EEXIST) {
- LOGE("'open' function error [%d] : <%s>", err, strerror(err));
+ LOGE("File <%s> : 'open' function error [%d] : <%s>", filename.c_str(), err,
+ strerror(err));
throw UnexpectedErrorException(err, strerror(err));
} else {
throw CannotCreateFileException(filename);
@@ -194,9 +196,12 @@ void Integrity::createPrimaryHardLinks(const Buckets &buckets) {
}
const auto &indexFilename = m_dbPath + m_indexFilename;
+ const auto &checksumFilename = m_dbPath + PathConfig::StoragePath::checksumFilename;
deleteHardLink(indexFilename);
createHardLink(indexFilename + m_backupFilenameSuffix, indexFilename);
+ deleteHardLink(checksumFilename);
+ createHardLink(checksumFilename + m_backupFilenameSuffix, checksumFilename);
}
void Integrity::deleteBackupHardLinks(const Buckets &buckets) {
@@ -209,6 +214,7 @@ void Integrity::deleteBackupHardLinks(const Buckets &buckets) {
}
deleteHardLink(m_dbPath + m_indexFilename + m_backupFilenameSuffix);
+ deleteHardLink(m_dbPath + PathConfig::StoragePath::checksumFilename + m_backupFilenameSuffix);
}
void Integrity::createHardLink(const std::string &oldName, const std::string &newName) {
diff --git a/test/db/db2/checksum b/test/db/db2/checksum
new file mode 100644
index 0000000..a91e13a
--- /dev/null
+++ b/test/db/db2/checksum
@@ -0,0 +1 @@
+buckets;$1$$QYBGLyef4xp18EzYIMd/U0
diff --git a/test/db/db3/checksum b/test/db/db3/checksum
new file mode 100644
index 0000000..39a8d89
--- /dev/null
+++ b/test/db/db3/checksum
@@ -0,0 +1,2 @@
+buckets;$1$$QYBGLyef4xp18EzYIMd/U0
+_;$1$$qRPK7m23GJusamGpoGLby/
diff --git a/test/db/db4/checksum b/test/db/db4/checksum
new file mode 100644
index 0000000..e2477f0
--- /dev/null
+++ b/test/db/db4/checksum
@@ -0,0 +1,3 @@
+buckets;$1$$Z6OUrCl62KbAaZ16Cexgm0
+_;$1$$qRPK7m23GJusamGpoGLby/
+_additional;$1$$qRPK7m23GJusamGpoGLby/
diff --git a/test/db/db5/checksum b/test/db/db5/checksum
new file mode 100644
index 0000000..b578233
--- /dev/null
+++ b/test/db/db5/checksum
@@ -0,0 +1,3 @@
+buckets;$1$$Z6OUrCl62KbAaZ16Cexgm0
+_;$1$$qRPK7m23GJusamGpoGLby/
+_additional;$1$$NIRf1PrhNP0QOAOGJ4VDf/
diff --git a/test/db/db6/checksum b/test/db/db6/checksum
new file mode 100644
index 0000000..a951841
--- /dev/null
+++ b/test/db/db6/checksum
@@ -0,0 +1,3 @@
+buckets;$1$$Z6OUrCl62KbAaZ16Cexgm0
+_;$1$$qRPK7m23GJusamGpoGLby/
+_additional;$1$$Shj03wOSJf.nmFjldRTO.1
diff --git a/test/db/db6/checksum~ b/test/db/db6/checksum~
new file mode 100644
index 0000000..e2477f0
--- /dev/null
+++ b/test/db/db6/checksum~
@@ -0,0 +1,3 @@
+buckets;$1$$Z6OUrCl62KbAaZ16Cexgm0
+_;$1$$qRPK7m23GJusamGpoGLby/
+_additional;$1$$qRPK7m23GJusamGpoGLby/
--
2.7.4
From e47f0b094278df45f6d38483718fafeba4d558d0 Mon Sep 17 00:00:00 2001
From: Pawel Wieczorek
Date: Thu, 15 Jan 2015 10:53:18 +0100
Subject: [PATCH 15/16] Adjust InMemoryStorageBackend to ChecksumStream
Now InMemoryStorageBackend uses ChecksumStream instead of std::ofstream.
New member function dumpDatabase() was introduced in order to destruct
database index stream before calling integrity mechanism.
Change-Id: I5ea943e1ec21f02cea97699993ddbd0f3eeb0a62
---
src/storage/InMemoryStorageBackend.cpp | 43 +++++++++++++++++-----------------
src/storage/InMemoryStorageBackend.h | 24 +++++++++++++++----
2 files changed, 40 insertions(+), 27 deletions(-)
diff --git a/src/storage/InMemoryStorageBackend.cpp b/src/storage/InMemoryStorageBackend.cpp
index 249eccf..57a4b56 100644
--- a/src/storage/InMemoryStorageBackend.cpp
+++ b/src/storage/InMemoryStorageBackend.cpp
@@ -35,7 +35,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -105,13 +104,11 @@ void InMemoryStorageBackend::load(void) {
}
void InMemoryStorageBackend::save(void) {
- auto indexStream = std::make_shared();
- std::string indexFilename = m_dbPath + m_indexFilename;
- openDumpFileStream(indexStream, indexFilename + m_backupFilenameSuffix);
+ std::string checksumFilename = m_dbPath + m_chsFilename;
+ auto chsStream = std::make_shared();
+ openDumpFileStream(chsStream, checksumFilename + m_backupFilenameSuffix);
- StorageSerializer storageSerializer(indexStream);
- storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
- this, std::placeholders::_1));
+ dumpDatabase(chsStream);
m_integrity.syncDatabase(buckets(), true);
m_integrity.createBackupGuard();
@@ -230,7 +227,17 @@ void InMemoryStorageBackend::erasePolicies(const PolicyBucketId &bucketId, bool
}
}
-void InMemoryStorageBackend::openFileStream(std::shared_ptr stream,
+void InMemoryStorageBackend::dumpDatabase(const std::shared_ptr &chsStream) {
+ auto indexStream = std::make_shared(m_indexFilename, chsStream);
+ std::string indexFilename = m_dbPath + m_indexFilename;
+ openDumpFileStream(indexStream, indexFilename + m_backupFilenameSuffix);
+
+ StorageSerializer storageSerializer(indexStream);
+ storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
+ this, std::placeholders::_1, chsStream));
+}
+
+void InMemoryStorageBackend::openFileStream(const std::shared_ptr &stream,
const std::string &filename, bool isBackupValid) {
// TODO: Consider adding exceptions to streams and handling them:
// stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
@@ -243,15 +250,6 @@ void InMemoryStorageBackend::openFileStream(std::shared_ptr strea
m_checksum.compare(*stream, filename, isBackupValid);
}
-void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr stream,
- const std::string &filename) {
- stream->open(filename, std::ofstream::out | std::ofstream::trunc);
-
- if (!stream->is_open()) {
- throw CannotCreateFileException(filename);
- }
-}
-
std::shared_ptr InMemoryStorageBackend::bucketStreamOpener(
const PolicyBucketId &bucketId, const std::string &filenameSuffix, bool isBackupValid) {
std::string bucketFilename = m_dbPath + m_bucketFilenamePrefix + bucketId + filenameSuffix;
@@ -266,14 +264,15 @@ std::shared_ptr InMemoryStorageBackend::bucketStreamOpener(
}
}
-std::shared_ptr > InMemoryStorageBackend::bucketDumpStreamOpener(
- const PolicyBucketId &bucketId) {
+std::shared_ptr > InMemoryStorageBackend::bucketDumpStreamOpener(
+ const PolicyBucketId &bucketId, const std::shared_ptr &chsStream) {
std::string bucketFilename = m_dbPath + m_bucketFilenamePrefix +
bucketId + m_backupFilenameSuffix;
- auto bucketStream = std::make_shared();
+ auto bucketStream = std::make_shared(m_bucketFilenamePrefix + bucketId,
+ chsStream);
- openDumpFileStream(bucketStream, bucketFilename);
- return std::make_shared >(bucketStream);
+ openDumpFileStream(bucketStream, bucketFilename);
+ return std::make_shared >(bucketStream);
}
void InMemoryStorageBackend::postLoadCleanup(bool isBackupValid) {
diff --git a/src/storage/InMemoryStorageBackend.h b/src/storage/InMemoryStorageBackend.h
index 65af96b..ea1f2bd 100644
--- a/src/storage/InMemoryStorageBackend.h
+++ b/src/storage/InMemoryStorageBackend.h
@@ -27,6 +27,7 @@
#include
#include
+#include
#include
#include
#include
@@ -35,6 +36,7 @@
#include
#include
+#include
#include