BareGit
#include "email_sender_file.h"

#include <atomic>
#include <cerrno>
#include <cstdint>
#include <cstring>
#include <filesystem>
#include <fcntl.h>
#include <string>
#include <system_error>
#include <unistd.h>

FileEmailSender::FileEmailSender(std::filesystem::path link_file)
    : link_file_(std::move(link_file))
{}

mw::E<void> FileEmailSender::send(const AuthenticationEmail& email)
{
    static std::atomic<std::uint64_t> next_temporary_id = 0;
    const std::uint64_t suffix = next_temporary_id.fetch_add(
        1, std::memory_order_relaxed);
    std::filesystem::path temporary = link_file_;
    temporary += ".tmp-" + std::to_string(::getpid()) + '-' +
        std::to_string(suffix);

    const int file = ::open(
        temporary.c_str(), O_WRONLY | O_CREAT | O_EXCL, 0600);
    if(file < 0)
    {
        return std::unexpected(mw::runtimeError(
            "Failed to write authentication link"));
    }
    const std::string contents = email.confirmation_url.str() + "\n";
    std::size_t written = 0;
    while(written < contents.size())
    {
        const ssize_t count = ::write(
            file, contents.data() + written, contents.size() - written);
        if(count < 0 && errno == EINTR)
        {
            continue;
        }
        if(count <= 0)
        {
            ::close(file);
            std::error_code ignored;
            std::filesystem::remove(temporary, ignored);
            return std::unexpected(mw::runtimeError(
                "Failed to write authentication link"));
        }
        written += static_cast<std::size_t>(count);
    }
    if(::fsync(file) != 0 || ::close(file) != 0)
    {
        std::error_code ignored;
        std::filesystem::remove(temporary, ignored);
        return std::unexpected(mw::runtimeError(
            "Failed to write authentication link"));
    }

    std::error_code error;
    std::filesystem::rename(temporary, link_file_, error);
    if(error)
    {
        std::error_code ignored;
        std::filesystem::remove(temporary, ignored);
        return std::unexpected(mw::runtimeError(
            "Failed to publish authentication link"));
    }
    return {};
}

bool FileEmailSender::usesGlobalQuota() const
{
    return false;
}