diff options
author | Vsevolod Stakhov <vsevolod@rspamd.com> | 2022-10-17 11:07:58 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rspamd.com> | 2022-10-17 11:07:58 +0100 |
commit | 14b52f4498c10625f3c16101cd34dec25a59bac6 (patch) | |
tree | 4e0c3fda002e492eac42bb6dd1092a13609de3a2 /src/libutil/cxx/file_util.hxx | |
parent | ff6390071ddb37e7ddeb9e058ef0831636e75841 (diff) | |
download | rspamd-14b52f4498c10625f3c16101cd34dec25a59bac6.tar.gz rspamd-14b52f4498c10625f3c16101cd34dec25a59bac6.zip |
[Minor] Rename file to a more appropriate name
Diffstat (limited to 'src/libutil/cxx/file_util.hxx')
-rw-r--r-- | src/libutil/cxx/file_util.hxx | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/src/libutil/cxx/file_util.hxx b/src/libutil/cxx/file_util.hxx new file mode 100644 index 000000000..c66fd17ef --- /dev/null +++ b/src/libutil/cxx/file_util.hxx @@ -0,0 +1,261 @@ +/*- + * Copyright 2022 Vsevolod Stakhov + * + * 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. + */ +#ifndef RSPAMD_FILE_UTIL_HXX +#define RSPAMD_FILE_UTIL_HXX +#pragma once + +#include "config.h" +#include "contrib/expected/expected.hpp" +#include <string> +#include <sys/stat.h> + +namespace rspamd::util { +/** + * A simple RAII object to contain a move only file descriptor + * A file is unlocked and closed when not needed + */ +struct raii_file { +public: + virtual ~raii_file() noexcept; + + static auto open(const char *fname, int flags) -> tl::expected<raii_file, std::string>; + static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_file, std::string>; + static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_file, std::string>; + static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_file, std::string>; + + auto get_fd() const -> int { + return fd; + } + + auto get_stat() const -> const struct stat& { + return st; + }; + + auto get_size() const -> std::size_t { + return st.st_size; + }; + + 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_file& operator=(raii_file &&other) noexcept { + std::swap(fd, other.fd); + std::swap(temp, other.temp); + std::swap(fname, other.fname); + std::swap(st, other.st); + + return *this; + } + + raii_file(raii_file &&other) noexcept { + *this = std::move(other); + } + + /** + * Prevent file from being deleted + * @return + */ + auto make_immortal() noexcept { + temp = false; + } + + /** + * Performs fstat on an opened file to refresh internal stat + * @return + */ + auto update_stat() noexcept -> bool; + + auto is_valid() noexcept -> bool { + return fd != -1; + } + + /* Do not allow copy/default ctor */ + const raii_file& operator=(const raii_file &other) = delete; + raii_file() = delete; + raii_file(const raii_file &other) = delete; +protected: + int fd = -1; + bool temp; + std::string fname; + struct stat st; + + explicit raii_file(const char *fname, int fd, bool temp) : fd(fd), temp(temp), fname(fname) {} +}; +/** + * A simple RAII object to contain a file descriptor with an flock wrap + * A file is unlocked and closed when not needed + */ +struct raii_locked_file final : public raii_file { +public: + ~raii_locked_file() noexcept override; + + static auto open(const char *fname, int flags) -> tl::expected<raii_locked_file, std::string> { + auto locked = raii_file::open(fname, flags).and_then([]<class T>(T &&file) { + return lock_raii_file(std::forward<T>(file)); + }); + + return locked; + } + static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_locked_file, std::string> { + auto locked = raii_file::create(fname, flags, perms).and_then([]<class T>(T &&file) { + return lock_raii_file(std::forward<T>(file)); + }); + + return locked; + } + static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_locked_file, std::string> { + auto locked = raii_file::create_temp(fname, flags, perms).and_then([]<class T>(T &&file) { + return lock_raii_file(std::forward<T>(file)); + }); + + return locked; + } + static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_locked_file, std::string> { + auto locked = raii_file::mkstemp(pattern, flags, perms).and_then([]<class T>(T &&file) { + return lock_raii_file(std::forward<T>(file)); + }); + + return locked; + } + + raii_locked_file& operator=(raii_locked_file &&other) noexcept { + std::swap(fd, other.fd); + std::swap(temp, other.temp); + std::swap(fname, other.fname); + std::swap(st, other.st); + + return *this; + } + + /** + * Unlock a locked file and return back unlocked file transferring ownership. + * A locked file cannot be used after this method. + */ + auto unlock() -> raii_file; + + raii_locked_file(raii_locked_file &&other) noexcept : raii_file(static_cast<raii_file &&>(std::move(other))) {} + /* Do not allow copy/default ctor */ + const raii_locked_file& operator=(const raii_locked_file &other) = delete; + raii_locked_file() = delete; + raii_locked_file(const raii_locked_file &other) = delete; +private: + static auto lock_raii_file(raii_file &&unlocked) -> tl::expected<raii_locked_file, std::string>; + raii_locked_file(raii_file &&other) noexcept : raii_file(std::move(other)) {} + explicit raii_locked_file(const char *fname, int fd, bool temp) : raii_file(fname, fd, temp) {} +}; + +/** + * A mmap wrapper on top of a locked file + */ +struct raii_mmaped_file final { + ~raii_mmaped_file(); + static auto mmap_shared(raii_file &&file, int flags) -> tl::expected<raii_mmaped_file, std::string>; + static auto mmap_shared(const char *fname, int open_flags, int mmap_flags) -> tl::expected<raii_mmaped_file, std::string>; + // Returns a constant pointer to the underlying map + auto get_map() const -> void* {return map;} + auto get_file() const -> const raii_file& { return file; } + // Passes the ownership of the mmaped memory to the callee + auto steal_map() -> std::tuple<void *, std::size_t> { + auto ret = std::make_tuple(this->map, file.get_stat().st_size); + this->map = nullptr; + return ret; + } + + auto get_size() const -> std::size_t { return file.get_stat().st_size; } + + raii_mmaped_file& operator=(raii_mmaped_file &&other) noexcept { + std::swap(map, other.map); + file = std::move(other.file); + + return *this; + } + + raii_mmaped_file(raii_mmaped_file &&other) noexcept; + + /* Do not allow copy/default ctor */ + const raii_mmaped_file& operator=(const raii_mmaped_file &other) = delete; + raii_mmaped_file() = delete; + raii_mmaped_file(const raii_mmaped_file &other) = delete; +private: + /* Is intended to be used with map_shared */ + explicit raii_mmaped_file(raii_file &&_file, void *_map); + raii_file file; + void *map = nullptr; +}; + +/** + * A helper to have a file to write that will be renamed to the + * target file if successful or deleted in the case of failure + */ +struct raii_file_sink final { + static auto create(const char *fname, int flags, int perms, const char *suffix = "new") + -> tl::expected<raii_file_sink, std::string>; + auto write_output() -> bool; + ~raii_file_sink(); + auto get_fd() const -> int + { + return file.get_fd(); + } + + raii_file_sink(raii_file_sink &&other) noexcept; + /* Do not allow copy/default ctor */ + const raii_file_sink& operator=(const raii_file_sink &other) = delete; + raii_file_sink() = delete; + raii_file_sink(const raii_file_sink &other) = delete; +private: + explicit raii_file_sink(raii_locked_file &&_file, const char *_output, std::string &&_tmp_fname); + raii_locked_file file; + std::string output_fname; + std::string tmp_fname; + bool success; +}; + +} + +#endif //RSPAMD_FILE_UTIL_HXX |