1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//
#ifndef OPENVPN_COMMON_TEMPFILE_H
#define OPENVPN_COMMON_TEMPFILE_H
#include <openvpn/common/platform.hpp>
#if defined(OPENVPN_PLATFORM_WIN)
#error temporary file methods not supported on Windows
#endif
#include <stdlib.h>
#include <errno.h>
#include <cstring> // for memcpy
#include <unistd.h> // for write, unlink, lseek
#include <sys/types.h> // for lseek
#include <string>
#include <memory>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/numeric_cast.hpp>
#include <openvpn/common/scoped_fd.hpp>
#include <openvpn/common/write.hpp>
#include <openvpn/common/strerror.hpp>
#include <openvpn/buffer/bufread.hpp>
using openvpn::numeric_util::numeric_cast;
namespace openvpn {
class TempFile
{
public:
OPENVPN_EXCEPTION(tempfile_exception);
TempFile(const std::string &fn_template,
const bool fn_delete)
: fn(new char[fn_template.length() + 1]),
del(fn_delete)
{
constexpr char pattern[] = "XXXXXX";
constexpr size_t patternLen = sizeof(pattern) - 1;
std::memcpy(fn.get(), fn_template.c_str(), fn_template.length() + 1);
const size_t pos = fn_template.rfind(pattern);
if (pos != std::string::npos)
{
if (fn_template.length() > pos + patternLen)
{
const auto suffixlen = fn_template.length() - pos - patternLen;
fd.reset(::mkstemps(fn.get(), numeric_cast<int>(suffixlen)));
}
else
fd.reset(::mkstemp(fn.get()));
if (!fd.defined())
{
const int eno = errno;
OPENVPN_THROW(tempfile_exception, "error creating temporary file from template: " << fn_template << " : " << strerror_str(eno));
}
}
else
OPENVPN_THROW(tempfile_exception, "badly formed temporary file template: " << fn_template);
}
~TempFile()
{
fd.close();
delete_file();
}
void reset()
{
const off_t off = ::lseek(fd(), 0, SEEK_SET);
if (off < 0)
{
const int eno = errno;
OPENVPN_THROW(tempfile_exception, "seek error on temporary file: " << filename() << " : " << strerror_str(eno));
}
if (off)
OPENVPN_THROW(tempfile_exception, "unexpected seek on temporary file: " << filename());
}
void truncate()
{
reset();
if (::ftruncate(fd(), 0) < 0)
{
const int eno = errno;
OPENVPN_THROW(tempfile_exception, "ftruncate error on temporary file: " << filename() << " : " << strerror_str(eno));
}
}
void write(const std::string &content)
{
const ssize_t size = write_retry(fd(), content.c_str(), content.length());
if (size < 0)
{
const int eno = errno;
OPENVPN_THROW(tempfile_exception, "error writing to temporary file: " << filename() << " : " << strerror_str(eno));
}
else if (static_cast<std::string::size_type>(size) != content.length())
{
OPENVPN_THROW(tempfile_exception, "incomplete write to temporary file: " << filename());
}
}
std::string read()
{
BufferList buflist = buf_read(fd(), filename());
return buflist.to_string();
}
std::string filename() const
{
if (fn)
return fn.get();
else
return "";
}
void close_file()
{
if (!fd.close())
{
const int eno = errno;
OPENVPN_THROW(tempfile_exception, "error closing temporary file: " << filename() << " : " << strerror_str(eno));
}
}
void set_delete(const bool del_flag)
{
del = del_flag;
}
void delete_file()
{
if (fn && del)
{
::unlink(fn.get());
del = false;
}
}
ScopedFD fd;
private:
std::unique_ptr<char[]> fn;
bool del;
};
} // namespace openvpn
#endif
|