#include "print_content.hpp"
#include "serialized_convert.hpp"
#include "tslog.hpp"
+#include "transaction_guard.hpp"
#include "include/fb_generated.h"
class StorageBackendSerialized::StorageBackendSerializedImpl {
int fd{-1};
- uint8_t *mem{nullptr};
+ uint8_t *mem{static_cast<decltype(mem)>(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;
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<decltype(mem)>(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<uint8_t*>(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 {
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() {
--- /dev/null
+#pragma once
+
+namespace transaction_guard {
+
+/* Helping class for automatically releasing acquired resources when transaction
+ * during initialization failed at some point.
+ */
+template <typename FunRelease>
+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 <typename FunRelease>
+Guard<FunRelease> makeGuard(FunRelease f) {
+ return Guard<FunRelease>(std::move(f));
+}
+
+} // namespace transaction_guard