OpenVPN 3 Core Library
Loading...
Searching...
No Matches
file.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// Basic file-handling methods.
13
14#ifndef OPENVPN_COMMON_FILE_H
15#define OPENVPN_COMMON_FILE_H
16
17#include <string>
18#include <fstream>
19#include <iostream>
20#include <cstdint> // for std::uint64_t
21
27
28#if defined(OPENVPN_PLATFORM_WIN)
29#include <filesystem>
31#endif
32
33
34namespace openvpn {
35
37OPENVPN_UNTAGGED_EXCEPTION_INHERIT(file_exception, open_file_error);
38OPENVPN_UNTAGGED_EXCEPTION_INHERIT(file_exception, file_too_large);
39OPENVPN_UNTAGGED_EXCEPTION_INHERIT(file_exception, file_is_binary);
40OPENVPN_UNTAGGED_EXCEPTION_INHERIT(file_exception, file_not_utf8);
41
42// Read text from file via stream approach that doesn't require that we
43// establish the length of the file in advance.
44inline std::string read_text_simple(const std::string &filename)
45{
46 std::ifstream ifs(filename.c_str());
47 if (!ifs)
48 OPENVPN_THROW(open_file_error, "cannot open for read: " << filename);
49 const std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
50 if (!ifs)
51 OPENVPN_THROW(open_file_error, "cannot read: " << filename);
52 return str;
53}
54
55// Read a file (may be text or binary).
56inline BufferPtr read_binary(const std::string &filename,
57 const std::uint64_t max_size = 0,
58 const unsigned int buffer_flags = 0)
59{
60#if defined(OPENVPN_PLATFORM_WIN)
61 Win::UTF16 filenamew(Win::utf16(filename));
62 std::filesystem::path path(filenamew.get());
63 std::ifstream ifs(path, std::ios::binary);
64#else
65 std::ifstream ifs(filename.c_str(), std::ios::binary);
66#endif // OPENVPN_PLATFORM_WIN
67
68 if (!ifs)
69 OPENVPN_THROW(open_file_error, "cannot open for read: " << filename);
70
71 // get length of file
72 ifs.seekg(0, std::ios::end);
73 const std::streamsize length = ifs.tellg();
74 if (max_size && std::uint64_t(length) > max_size)
75 OPENVPN_THROW(file_too_large, "file too large [" << length << '/' << max_size << "]: " << filename);
76 ifs.seekg(0, std::ios::beg);
77
78 // allocate buffer
79 auto b = BufferAllocatedRc::Create(size_t(length), buffer_flags | BufAllocFlags::ARRAY);
80
81 // read data
82 ifs.read((char *)b->data(), length);
83
84 // check for errors
85 if (ifs.gcount() != length)
86 OPENVPN_THROW(open_file_error, "read length inconsistency: " << filename);
87 if (!ifs)
88 OPENVPN_THROW(open_file_error, "cannot read: " << filename);
89
90 return b;
91}
92
93// Read a file (may be text or binary) without seeking to determine
94// its length.
95inline BufferPtr read_binary_linear(const std::string &filename,
96 const std::uint64_t max_size = 0,
97 const size_t block_size = 1024)
98{
99 std::ifstream ifs(filename.c_str(), std::ios::binary);
100 if (!ifs)
101 OPENVPN_THROW(open_file_error, "cannot open for read: " << filename);
102
103 BufferList buflist;
104 std::streamsize total_size = 0;
105 while (true)
106 {
107 auto b = BufferAllocatedRc::Create(block_size, 0);
108 ifs.read((char *)b->data(), b->remaining());
109 const std::streamsize size = ifs.gcount();
110 if (size)
111 {
112 b->set_size(static_cast<size_t>(size));
113 total_size += size;
114 if (max_size && std::uint64_t(total_size) > max_size)
115 OPENVPN_THROW(file_too_large, "file too large [" << total_size << '/' << max_size << "]: " << filename);
116 buflist.push_back(std::move(b));
117 }
118 if (ifs.eof())
119 break;
120 if (!ifs)
121 OPENVPN_THROW(open_file_error, "cannot read: " << filename);
122 }
123 return buflist.join();
124}
125
126// Read a text file as a std::string, throw error if file is binary
127inline std::string read_text(const std::string &filename, const std::uint64_t max_size = 0)
128{
129 BufferPtr bp = read_binary(filename, max_size);
130 if (bp->contains_null())
131 OPENVPN_THROW(file_is_binary, "file is binary: " << filename);
132 return std::string((const char *)bp->c_data(), bp->size());
133}
134
135// Read a UTF-8 file as a std::string, throw errors if file is binary or malformed UTF-8
136inline std::string read_text_utf8(const std::string &filename, const std::uint64_t max_size = 0)
137{
138 BufferPtr bp = read_binary(filename, max_size);
139
140 // check if binary
141 if (bp->contains_null())
142 OPENVPN_THROW(file_is_binary, "file is binary: " << filename);
143
144 // remove Windows UTF-8 BOM if present
145 if (bp->size() >= 3)
146 {
147 const unsigned char *data = bp->c_data();
148 if (data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF)
149 bp->advance(3);
150 }
151
152 // verify that file is valid UTF-8
153 if (!Unicode::is_valid_utf8_uchar_buf(bp->c_data(), bp->size()))
154 OPENVPN_THROW(file_not_utf8, "file is not UTF8: " << filename);
155
156 return std::string((const char *)bp->c_data(), bp->size());
157}
158
159// Read multi-line string from stdin
160inline std::string read_stdin()
161{
162 std::string ret;
163 std::string line;
164 while (std::getline(std::cin, line))
165 {
166 ret += line;
167 ret += '\n';
168 }
169 return ret;
170}
171
172// Write binary buffer to file
173inline void write_binary(const std::string &filename, const Buffer &buf)
174{
175 std::ofstream ofs(filename.c_str(), std::ios::binary);
176 if (!ofs)
177 OPENVPN_THROW(open_file_error, "cannot open for write: " << filename);
178 ofs.write((const char *)buf.c_data(), buf.size());
179 if (!ofs)
180 OPENVPN_THROW(open_file_error, "cannot write: " << filename);
181}
182
183// Write binary buffer list to file
184template <typename BUFLIST>
185inline void write_binary_list(const std::string &filename, const BUFLIST &buflist)
186{
187 std::ofstream ofs(filename.c_str(), std::ios::binary);
188 if (!ofs)
189 OPENVPN_THROW(open_file_error, "cannot open for write: " << filename);
190 for (auto &buf : buflist)
191 {
192 ofs.write((const char *)buf->c_data(), buf->size());
193 if (!ofs)
194 OPENVPN_THROW(open_file_error, "cannot write: " << filename);
195 }
196}
197
198// Write std::string to file
199inline void write_string(const std::string &filename, const std::string &str)
200{
201 BufferPtr buf = buf_from_string(str);
202 write_binary(filename, *buf);
203}
204
205} // namespace openvpn
206
207#endif // OPENVPN_COMMON_FILE_H
const T * c_data() const
Returns a const pointer to the start of the buffer.
Definition buffer.hpp:1177
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1225
static Ptr Create(ArgsT &&...args)
Creates a new instance of RcEnable with the given arguments.
Definition make_rc.hpp:43
#define OPENVPN_UNTAGGED_EXCEPTION(C)
#define OPENVPN_UNTAGGED_EXCEPTION_INHERIT(B, C)
#define OPENVPN_THROW(exc, stuff)
bool is_valid_utf8_uchar_buf(const unsigned char *source, size_t size, const size_t max_len_flags=0)
Definition unicode.hpp:41
std::unique_ptr< wchar_t[]> UTF16
Definition unicode.hpp:24
wchar_t * utf16(const std::string &str, int cp=CP_UTF8)
Definition unicode.hpp:29
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
std::string read_text(const std::string &filename, const std::uint64_t max_size=0)
Definition file.hpp:127
std::string read_text_utf8(const std::string &filename, const std::uint64_t max_size=0)
Definition file.hpp:136
BufferPtr read_binary_linear(const std::string &filename, const std::uint64_t max_size=0, const size_t block_size=1024)
Definition file.hpp:95
BufferPtr read_binary(const std::string &filename, const std::uint64_t max_size=0, const unsigned int buffer_flags=0)
Definition file.hpp:56
std::string read_stdin()
Definition file.hpp:160
void write_binary(const std::string &filename, const Buffer &buf)
Definition file.hpp:173
void write_string(const std::string &filename, const std::string &str)
Definition file.hpp:199
std::string read_text_simple(const std::string &filename)
Definition file.hpp:44
BufferPtr buf_from_string(const std::string &str)
Definition bufstr.hpp:46
void write_binary_list(const std::string &filename, const BUFLIST &buflist)
Definition file.hpp:185
@ ARRAY
if enabled, use as array
Definition buffer.hpp:873
BufferPtr join(const size_t headroom, const size_t tailroom, const bool size_1_optim) const
Definition buflist.hpp:32
std::string ret