commit 2e108c5: [Minor] Add some more methods and tests to the file raii abstraction
Vsevolod Stakhov
vsevolod at rspamd.com
Sat Oct 8 14:49:05 UTC 2022
Author: Vsevolod Stakhov
Date: 2022-10-08 15:19:11 +0100
URL: https://github.com/rspamd/rspamd/commit/2e108c577370151e9ee0b063de1963e05c4a3522
[Minor] Add some more methods and tests to the file raii abstraction
---
src/libutil/cxx/locked_file.cxx | 66 +++++++++++++++++++++++++++++++++++++++--
src/libutil/cxx/locked_file.hxx | 38 ++++++++++++++++++++++++
2 files changed, 101 insertions(+), 3 deletions(-)
diff --git a/src/libutil/cxx/locked_file.cxx b/src/libutil/cxx/locked_file.cxx
index 6abc4a1b0..bd25b0fc7 100644
--- a/src/libutil/cxx/locked_file.cxx
+++ b/src/libutil/cxx/locked_file.cxx
@@ -127,6 +127,40 @@ auto raii_locked_file::create_temp(const char *fname, int flags, int perms) -> t
return ret;
}
+auto raii_locked_file::mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_locked_file, std::string>
+{
+ int oflags = flags;
+#ifdef O_CLOEXEC
+ oflags |= O_CLOEXEC | O_CREAT | O_EXCL;
+#endif
+ if (pattern == nullptr) {
+ return tl::make_unexpected("cannot open file; pattern is nullptr");
+ }
+
+ std::string mutable_pattern = pattern;
+
+ auto fd = g_mkstemp_full(mutable_pattern.data(), oflags, perms);
+
+ if (fd == -1) {
+ return tl::make_unexpected(fmt::format("cannot create file {}: {}", pattern, ::strerror(errno)));
+ }
+
+ if (!rspamd_file_lock(fd, TRUE)) {
+ close(fd);
+ (void)unlink(mutable_pattern.c_str());
+ return tl::make_unexpected(fmt::format("cannot lock file {}: {}", pattern, ::strerror(errno)));
+ }
+
+ auto ret = raii_locked_file{mutable_pattern.c_str(), fd, true};
+
+ if (fstat(ret.fd, &ret.st) == -1) {
+ return tl::make_unexpected(fmt::format("cannot stat file {}: {}",
+ mutable_pattern.c_str(), ::strerror(errno)));
+ }
+
+ return ret;
+}
+
raii_mmaped_locked_file::raii_mmaped_locked_file(raii_locked_file &&_file, void *_map)
: file(std::move(_file)), map(_map)
{
@@ -242,7 +276,7 @@ static auto test_write_file(const T& f, const std::string_view &buf) {
(void)::lseek(fd, 0, SEEK_SET);
return ::write(fd, buf.data(), buf.size());
}
-auto random_fname() {
+auto random_fname(std::string_view extension) {
const auto *tmpdir = getenv("TMPDIR");
if (tmpdir == nullptr) {
tmpdir = G_DIR_SEPARATOR_S "tmp";
@@ -254,16 +288,21 @@ auto random_fname() {
unsigned char hexbuf[32];
rspamd_random_hex(hexbuf, sizeof(hexbuf));
out_fname.append((const char *)hexbuf, sizeof(hexbuf));
+ if (!extension.empty()) {
+ out_fname.append(".");
+ out_fname.append(extension);
+ }
return out_fname;
}
TEST_SUITE("loked files utils") {
TEST_CASE("create and delete file") {
- auto fname = random_fname();
+ auto fname = random_fname("tmp");
{
auto raii_locked_file = raii_locked_file::create_temp(fname.c_str(), O_RDONLY, 00600);
CHECK(raii_locked_file.has_value());
+ CHECK(raii_locked_file.value().get_extension() == "tmp");
CHECK(::access(fname.c_str(), R_OK) == 0);
}
// File must be deleted after this call
@@ -284,10 +323,11 @@ TEST_CASE("create and delete file") {
}
TEST_CASE("check lock") {
- auto fname = random_fname();
+ auto fname = random_fname("");
{
auto raii_locked_file = raii_locked_file::create_temp(fname.c_str(), O_RDONLY, 00600);
CHECK(raii_locked_file.has_value());
+ CHECK(raii_locked_file.value().get_extension() == "");
CHECK(::access(fname.c_str(), R_OK) == 0);
auto raii_locked_file2 = raii_locked_file::open(fname.c_str(), O_RDONLY);
CHECK(!raii_locked_file2.has_value());
@@ -300,6 +340,26 @@ TEST_CASE("check lock") {
CHECK(serrno == ENOENT);
}
+TEST_CASE("tempfile") {
+ std::string tmpname;
+ {
+ auto raii_locked_file = raii_locked_file::mkstemp("/tmp//doctest-XXXXXXXX",
+ O_RDONLY, 00600);
+ CHECK(raii_locked_file.has_value());
+ CHECK(raii_locked_file.value().get_dir() == "/tmp");
+ CHECK(access(raii_locked_file.value().get_name().data(), R_OK) == 0);
+ auto raii_locked_file2 = raii_locked_file::open(raii_locked_file.value().get_name().data(), O_RDONLY);
+ CHECK(!raii_locked_file2.has_value());
+ CHECK(access(raii_locked_file.value().get_name().data(), R_OK) == 0);
+ tmpname = raii_locked_file.value().get_name();
+ }
+ // File must be deleted after this call
+ auto ret = ::access(tmpname.c_str(), R_OK);
+ auto serrno = errno;
+ CHECK(ret == -1);
+ CHECK(serrno == ENOENT);
+}
+
} // TEST_SUITE
} // namespace tests
diff --git a/src/libutil/cxx/locked_file.hxx b/src/libutil/cxx/locked_file.hxx
index 6ac4ffd2c..ce25b0a5a 100644
--- a/src/libutil/cxx/locked_file.hxx
+++ b/src/libutil/cxx/locked_file.hxx
@@ -17,6 +17,7 @@
#define RSPAMD_LOCKED_FILE_HXX
#pragma once
+#include "config.h"
#include "contrib/expected/expected.hpp"
#include <string>
#include <sys/stat.h>
@@ -32,6 +33,7 @@ struct raii_locked_file final {
static auto open(const char *fname, int flags) -> tl::expected<raii_locked_file, std::string>;
static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_locked_file, std::string>;
static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_locked_file, std::string>;
+ static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_locked_file, std::string>;
auto get_fd() const -> int {
return fd;
@@ -41,6 +43,42 @@ struct raii_locked_file final {
return st;
};
+ auto get_name() const -> std::string_view {
+ return std::string_view{fname};
+ }
+
+ auto get_dir() const -> std::string_view {
+ auto sep_pos = fname.rfind(G_DIR_SEPARATOR);
+
+ if (sep_pos == std::string::npos) {
+ return std::string_view{fname};
+ }
+
+ while (sep_pos >= 1 && fname[sep_pos - 1] == G_DIR_SEPARATOR) {
+ sep_pos --;
+ }
+
+ return std::string_view{fname.c_str(), sep_pos};
+ }
+
+ auto get_extension() const -> std::string_view {
+ auto sep_pos = fname.rfind(G_DIR_SEPARATOR);
+
+ if (sep_pos == std::string::npos) {
+ sep_pos = 0;
+ }
+
+ auto filename = std::string_view{fname.c_str() + sep_pos};
+ auto dot_pos = filename.find('.');
+
+ if (dot_pos == std::string::npos) {
+ return std::string_view{};
+ }
+ else {
+ return std::string_view{filename.data() + dot_pos + 1, filename.size() - dot_pos - 1};
+ }
+ }
+
raii_locked_file& operator=(raii_locked_file &&other) noexcept {
std::swap(fd, other.fd);
std::swap(temp, other.temp);
More information about the Commits
mailing list