123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- /*
- * Copyright 2023 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 "libutil/cxx/error.hxx"
- #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, error>;
- static auto open(const std::string &fname, int flags) -> tl::expected<raii_file, error>
- {
- return open(fname.c_str(), flags);
- };
- static auto create(const char *fname, int flags, int perms) -> tl::expected<raii_file, error>;
- static auto create(const std::string &fname, int flags, int perms) -> tl::expected<raii_file, error>
- {
- return create(fname.c_str(), flags, perms);
- };
-
- static auto create_temp(const char *fname, int flags, int perms) -> tl::expected<raii_file, error>;
- static auto mkstemp(const char *pattern, int flags, int perms) -> tl::expected<raii_file, error>;
-
- 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 + 1};
- }
-
- 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);
- };
- /**
- * 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, error>
- {
- 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, error>
- {
- 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, error>
- {
- 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, error>
- {
- 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, error>;
- 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, std::int64_t offset = 0) -> tl::expected<raii_mmaped_file, error>;
- static auto mmap_shared(const char *fname, int open_flags, int mmap_flags, std::int64_t offset = 0) -> tl::expected<raii_mmaped_file, error>;
- // 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, map_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);
- std::swap(map_size, other.map_size);
- 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, std::size_t sz);
- raii_file file;
- void *map = nullptr;
- std::size_t map_size;
- };
-
- /**
- * 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, error>;
- 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;
- };
-
- }// namespace rspamd::util
-
- #endif//RSPAMD_FILE_UTIL_HXX
|