From ccc210535a56bbc0ebafa1d3fae97935ba62aa94 Mon Sep 17 00:00:00 2001 From: Adrian Szyndela Date: Thu, 21 Feb 2019 16:03:35 +0100 Subject: [PATCH] serialization: reworked init for serialized backend Change-Id: Ie72cf3444dfc7bf446bb6035df6a57d04ae0c180 --- src/internal/storage_backend_serialized.cpp | 107 ++++++++++++++++++---------- src/internal/storage_backend_serialized.hpp | 4 +- src/internal/transaction_guard.hpp | 37 ++++++++++ 3 files changed, 111 insertions(+), 37 deletions(-) create mode 100644 src/internal/transaction_guard.hpp diff --git a/src/internal/storage_backend_serialized.cpp b/src/internal/storage_backend_serialized.cpp index 96b4532..fb5ccda 100644 --- a/src/internal/storage_backend_serialized.cpp +++ b/src/internal/storage_backend_serialized.cpp @@ -2,6 +2,7 @@ #include "print_content.hpp" #include "serialized_convert.hpp" #include "tslog.hpp" +#include "transaction_guard.hpp" #include "include/fb_generated.h" @@ -25,11 +26,16 @@ struct type_helper; class StorageBackendSerialized::StorageBackendSerializedImpl { int fd{-1}; - uint8_t *mem{nullptr}; + uint8_t *mem{static_cast(MAP_FAILED)}; size_t length{0}; - const FB::File *file; + const FB::File *file{nullptr}; + + void releaseMMap(); + void releaseFD(); + public: - void init(const char *filename); + bool init(const char *filename, bool verify); + bool init(const FB::File *f); void release(); void printContent() const; @@ -38,57 +44,82 @@ public: const M *getPolicySet(); }; -void StorageBackendSerialized::StorageBackendSerializedImpl::release() { - if (nullptr != mem) { - if (munmap(mem, length) != 0) - tslog::log("munmap(): ", strerror(errno), "\n"); - mem = nullptr; - length = 0; - } +void StorageBackendSerialized::StorageBackendSerializedImpl::releaseMMap() { + assert(MAP_FAILED != mem); + assert(0 != length); + + if (munmap(mem, length) != 0) + tslog::log("munmap(): ", strerror(errno), "\n"); + + mem = static_cast(MAP_FAILED); + length = 0; +} - if (-1 != fd) { - if (close(fd) != 0) - tslog::log("close(): ", strerror(errno), "\n"); - fd = -1; +void StorageBackendSerialized::StorageBackendSerializedImpl::releaseFD() { + assert(-1 != fd); + + if (close(fd) != 0) + tslog::log("close(): ", strerror(errno), "\n"); + + fd = -1; +} + +void StorageBackendSerialized::StorageBackendSerializedImpl::release() { + if (-1 != fd) { // we need to check it, because we may have initialized the storage directly from File * + releaseMMap(); + releaseFD(); } file = nullptr; } -void StorageBackendSerialized::StorageBackendSerializedImpl::init(const char *filename) { +bool StorageBackendSerialized::StorageBackendSerializedImpl::init(const char *filename, bool verify) { + assert(nullptr == file); + auto err = [filename] (const char *what) { tslog::log("Can't ", what, " ", filename, ": ", strerror(errno), "\n"); + return false; }; fd = open(filename, O_RDONLY); - if (-1 == fd) { - err("open"); - return; - } + if (-1 == fd) + return err("open"); + + auto openGuard = transaction_guard::makeGuard([&] () { releaseFD(); }); struct stat buf; - if (fstat(fd, &buf) == -1) { - err("stat"); - close(fd); - return; - } + if (fstat(fd, &buf) == -1) + return err("stat"); length = buf.st_size; mem = reinterpret_cast(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0)); - if (MAP_FAILED == mem) { - err("mmap"); - close(fd); - return; + if (MAP_FAILED == mem) + return err("mmap"); + + auto mmapGuard = transaction_guard::makeGuard([&] () { releaseMMap(); }); + + if (verify) { + auto verifier = flatbuffers::Verifier(mem, length); + if (!FB::VerifyFileBuffer(verifier)) { + tslog::log("verification of serialized data: failed\n"); + return false; + } } -// TODO: decide - do we need verification? -// for verification: -// -// if (!VerifyFileBuffer(Verifier(mem, length))) -// bailout(); -// + + openGuard.dismiss(); + mmapGuard.dismiss(); + file = GetFile(mem); + return true; +} + +bool StorageBackendSerialized::StorageBackendSerializedImpl::init(const FB::File *f) { + assert(nullptr == file); + + file = f; + return true; } void StorageBackendSerialized::StorageBackendSerializedImpl::printContent() const { @@ -115,8 +146,12 @@ TYPE_HELPER(Send, send) TYPE_HELPER(Receive, receive) TYPE_HELPER(Access, access) -void StorageBackendSerialized::init(const char *filename) { - pimpl->init(filename); +bool StorageBackendSerialized::init(const char *filename, bool verify) { + return pimpl->init(filename, verify); +} + +bool StorageBackendSerialized::init(const FB::File *f) { + return pimpl->init(f); } void StorageBackendSerialized::release() { diff --git a/src/internal/storage_backend_serialized.hpp b/src/internal/storage_backend_serialized.hpp index 159994a..bf48dd7 100644 --- a/src/internal/storage_backend_serialized.hpp +++ b/src/internal/storage_backend_serialized.hpp @@ -1,6 +1,7 @@ #pragma once #include "policy.hpp" +#include "fb_generated.h" #include @@ -13,7 +14,8 @@ public: StorageBackendSerialized(); ~StorageBackendSerialized(); - void init(const char *filename); + bool init(const char *filename, bool verify = false); + bool init(const FB::File *file); void release(); void printContent() const; diff --git a/src/internal/transaction_guard.hpp b/src/internal/transaction_guard.hpp new file mode 100644 index 0000000..5fc20da --- /dev/null +++ b/src/internal/transaction_guard.hpp @@ -0,0 +1,37 @@ +#pragma once + +namespace transaction_guard { + +/* Helping class for automatically releasing acquired resources when transaction + * during initialization failed at some point. + */ +template +class Guard { + FunRelease fun; + bool active; +public: + Guard(FunRelease f) : fun(f), active(true) {} + Guard() = delete; + Guard(const Guard &) = delete; + Guard &operator=(const Guard &) = delete; + + ~Guard() { + if (active) + fun(); + } + + void dismiss() { + active = false; + } + + Guard(Guard &&g) : fun(std::move(g.fun)), active(g.active) { + dismiss(); + } +}; + +template +Guard makeGuard(FunRelease f) { + return Guard(std::move(f)); +} + +} // namespace transaction_guard -- 2.7.4