Switch license from Intranator license to GPLv2 + linking exception (ACKed by Steffen)
[libi2ncommon] / src / tmpfstream.hpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
52d6f7fc
GE
20/** @file
21 * @brief fstream which creates files with mkstemp.
22 *
23 * @author Gerd v. Egidy
24 *
25 * @copyright © Copyright 2010 by Intra2net AG
52d6f7fc
GE
26 */
27
28#ifndef __I2N_TMPFSTREAM_HPP__
29#define __I2N_TMPFSTREAM_HPP__
30
31#include <string>
32
33#include <boost/iostreams/detail/char_traits.hpp>
34#include <boost/config.hpp>
35#include <boost/iostreams/stream.hpp>
36#include <boost/iostreams/device/file_descriptor.hpp>
37
ef2a6062
GE
38#include <userfunc.hpp>
39
69d8da4a 40#include <sys/stat.h>
52d6f7fc
GE
41
42namespace I2n
43{
44
82b461e4
GE
45namespace bio = boost::iostreams;
46
69d8da4a
GE
47/**
48 * @brief fstream or ofstream which creates files with mkstemp
49 *
50 * This class becomes an std::ostream or std::stream depending on the
51 * @ref Device used.
52 * For the most common cases, use the provided typedefs @ref tmpofstream
53 * and @ref tmpfstream.
54 * The temporary file is created with permissions 0600. These can be changed
55 * with @ref set_file_mode.
56 *
57 * @param Device Class which implements the Device Concept of boost::iostreams
58 * and offers a function Open(filedescriptor,close_on_exit). Usually
59 * this is boost::iostreams::file_descriptor and
60 * boost::iostreams::file_descriptor_sink
61 * @param Tr Character traits type
62 * @param Alloc Allocator for the character buffers
63 */
52d6f7fc
GE
64template< typename Device,
65 typename Tr =
66 BOOST_IOSTREAMS_CHAR_TRAITS(
82b461e4 67 BOOST_DEDUCED_TYPENAME bio::char_type_of<Device>::type
52d6f7fc
GE
68 ),
69 typename Alloc =
70 std::allocator<
82b461e4 71 BOOST_DEDUCED_TYPENAME bio::char_type_of<Device>::type
52d6f7fc 72 > >
82b461e4 73class tmpfstreamTempl : public bio::stream<Device, Tr, Alloc>
52d6f7fc
GE
74{
75private:
ff09d317 76 std::string tmpfilename;
0fcb8655 77 bool unlinked;
f002679a 78 int fd;
52d6f7fc
GE
79
80public:
69d8da4a
GE
81 /**
82 * @brief Constructs an unopened tmpfstreamTempl.
83 */
82b461e4 84 tmpfstreamTempl()
7ac95d85 85 : unlinked(false), fd(-1), bio::stream<Device, Tr, Alloc>()
52d6f7fc
GE
86 { }
87
69d8da4a
GE
88 /**
89 * @brief Constructs and opens the tmpfstreamTempl.
90 *
91 * @param tmpnametemplate Path of the temporary file to be opened.
92 * The last 6 characters must be XXXXXX and they
93 * will be replaced with something random.
94 * @param mode std::ios_base::open_mode to open the file with
95 * @param buffer_size The size of any buffers that need to be allocated
96 * @param buffer_size The size of the putback buffer, relevant only for fstream
97 */
82b461e4 98 tmpfstreamTempl(const std::string& tmpnametemplate,
52d6f7fc
GE
99 std::ios_base::open_mode mode = std::ios_base::out,
100 int buffer_size = -1 , int pback_size = -1)
7ac95d85 101 : unlinked(false), fd(-1), bio::stream<Device, Tr, Alloc>()
52d6f7fc
GE
102 {
103 open(tmpnametemplate,mode,buffer_size,pback_size);
104 }
105
106 bool open(const std::string& tmpnametemplate,
107 std::ios_base::open_mode mode = std::ios_base::out,
82b461e4 108 int buffer_size = -1 , int pback_size = -1);
52d6f7fc 109
69d8da4a
GE
110 /**
111 * @brief Get the filename of the temporary file.
112 *
113 * @retval returns the filename really used with the XXXXXX replaced.
114 */
52d6f7fc 115 std::string get_tmp_filename()
ff09d317 116 { return tmpfilename; }
52d6f7fc 117
69d8da4a 118 bool set_file_mode(mode_t mode);
52d6f7fc 119
ef2a6062
GE
120 bool set_owner(const I2n::User& user, const I2n::Group& group= I2n::Group());
121
82b461e4 122 bool unlink();
52d6f7fc 123
0fcb8655
GE
124 bool is_unlinked()
125 { return unlinked; }
126
127 bool move(const std::string& targetpath, bool overwrite=false);
f002679a
GE
128
129 bool sync();
52d6f7fc
GE
130};
131
69d8da4a
GE
132
133/**
134 * @brief ofstream which creates files with mkstemp
135 */
136typedef tmpfstreamTempl<bio::file_descriptor_sink> tmpofstream;
137/**
138 * @brief fstream which creates files with mkstemp
139 */
140typedef tmpfstreamTempl<bio::file_descriptor> tmpfstream;
141
142/**
143 * @brief fstream or ofstream which first writes to a temp file and atomically
144 * replaces an old file on close.
145 *
146 * This class becomes an std::ostream or std::stream depending on the
147 * @ref Device used.
148 * For the most common cases, use the provided typedefs @ref tmpofcopystream
149 * and @ref tmpfcopystream.
150 * The temporary file is created with permissions 0600. On @ref close the
151 * permissions of the original file will be set to 0644 by default.
152 *
153 * @param Device Class which implements the Device Concept of boost::iostreams
154 * and offers a function Open(filedescriptor,close_on_exit). Usually
155 * this is boost::iostreams::file_descriptor and
156 * boost::iostreams::file_descriptor_sink
157 * @param Tr Character traits type
158 * @param Alloc Allocator for the character buffers
159 */
ff09d317
GE
160template< typename Device,
161 typename Tr =
162 BOOST_IOSTREAMS_CHAR_TRAITS(
163 BOOST_DEDUCED_TYPENAME bio::char_type_of<Device>::type
164 ),
165 typename Alloc =
166 std::allocator<
167 BOOST_DEDUCED_TYPENAME bio::char_type_of<Device>::type
168 > >
169class tmpfcopystreamTempl : public tmpfstreamTempl<Device, Tr, Alloc>
170{
171private:
172 std::string originalfilename;
173 bool full_sync;
69d8da4a 174 mode_t filemode_on_close;
ef2a6062
GE
175 I2n::User UserOnClose;
176 I2n::Group GroupOnClose;
ff09d317
GE
177
178public:
179 static const std::string default_template_suffix;
a8cbce97
GE
180 static const bool default_full_sync=false;
181 static const int default_filemode_on_close=0644;
ff09d317 182
69d8da4a
GE
183 /**
184 * @brief Constructs an unopened tmpfcopystreamTempl.
185 */
ff09d317 186 tmpfcopystreamTempl()
a8cbce97
GE
187 : full_sync(default_full_sync),
188 filemode_on_close(default_filemode_on_close),
ef2a6062 189 UserOnClose(), GroupOnClose(),
a8cbce97 190 tmpfstreamTempl<Device, Tr, Alloc>()
ff09d317
GE
191 { }
192
69d8da4a
GE
193 /**
194 * @brief Constructs and opens the tmpfcopystreamTempl.
195 *
196 * The temporary file will be in the same directory with .tmp.XXXXXX appended.
197 *
198 * @param filename The original filename which will be replaced on close
199 * @param mode std::ios_base::open_mode to open the file with
200 * @param buffer_size The size of any buffers that need to be allocated
201 * @param buffer_size The size of the putback buffer, relevant only for fstream
202 */
ff09d317
GE
203 tmpfcopystreamTempl(const std::string& filename,
204 std::ios_base::open_mode mode = std::ios_base::out,
205 int buffer_size = -1 , int pback_size = -1)
a8cbce97
GE
206 : full_sync(default_full_sync),
207 filemode_on_close(default_filemode_on_close),
ef2a6062 208 UserOnClose(), GroupOnClose(),
a8cbce97 209 originalfilename(filename),
ff09d317
GE
210 tmpfstreamTempl<Device, Tr, Alloc>
211 (filename+default_template_suffix,mode,buffer_size,pback_size)
212 { }
213
69d8da4a
GE
214 /**
215 * @brief Constructs and opens the tmpfcopystreamTempl.
216 *
217 * filename and tmpnametemplate must be on the same filesystem.
218 *
219 * @param filename The original filename which will be replaced on close
220 * @param tmpnametemplate Path of the temporary file to be opened.
221 * The last 6 characters must be XXXXXX and they
222 * will be replaced with something random.
223 * @param mode std::ios_base::open_mode to open the file with
224 * @param buffer_size The size of any buffers that need to be allocated
225 * @param buffer_size The size of the putback buffer, relevant only for fstream
226 */
ff09d317
GE
227 tmpfcopystreamTempl(const std::string& filename,
228 const std::string& tmpnametemplate,
229 std::ios_base::open_mode mode = std::ios_base::out,
230 int buffer_size = -1 , int pback_size = -1)
a8cbce97
GE
231 : full_sync(default_full_sync),
232 filemode_on_close(default_filemode_on_close),
ef2a6062 233 UserOnClose(), GroupOnClose(),
a8cbce97 234 originalfilename(filename),
ff09d317
GE
235 tmpfstreamTempl<Device, Tr, Alloc>
236 (tmpnametemplate,mode,buffer_size,pback_size)
237 { }
238
ccee68fd
GE
239 ~tmpfcopystreamTempl()
240 { close(); }
241
69d8da4a
GE
242 /**
243 * @brief Opens the tmpfcopystreamTempl.
244 *
245 * The temporary file will be in the same directory with .tmp.XXXXXX appended.
246 *
247 * @param filename The original filename which will be replaced on close
248 * @param mode std::ios_base::open_mode to open the file with
249 * @param buffer_size The size of any buffers that need to be allocated
250 * @param buffer_size The size of the putback buffer, relevant only for fstream
251 * @retval true if successful
252 */
ff09d317
GE
253 bool open(const std::string& filename,
254 std::ios_base::open_mode mode = std::ios_base::out,
255 int buffer_size = -1 , int pback_size = -1)
256 {
257 originalfilename=filename;
258 return tmpfstreamTempl<Device, Tr, Alloc>
259 ::open(filename+default_template_suffix,mode,buffer_size,pback_size);
260 }
261
69d8da4a
GE
262 /**
263 * @brief Opens the tmpfcopystreamTempl.
264 *
265 * filename and tmpnametemplate must be on the same filesystem.
266 *
267 * @param filename The original filename which will be replaced on close
268 * @param tmpnametemplate Path of the temporary file to be opened.
269 * The last 6 characters must be XXXXXX and they
270 * will be replaced with something random.
271 * @param mode std::ios_base::open_mode to open the file with
272 * @param buffer_size The size of any buffers that need to be allocated
273 * @param buffer_size The size of the putback buffer, relevant only for fstream
274 * @retval true if successful
275 */
ff09d317
GE
276 bool open(const std::string& filename,
277 const std::string& tmpnametemplate,
278 std::ios_base::open_mode mode = std::ios_base::out,
279 int buffer_size = -1 , int pback_size = -1)
280 {
281 originalfilename=filename;
282 return tmpfstreamTempl<Device, Tr, Alloc>
283 ::open(tmpnametemplate,mode,buffer_size,pback_size);
284 }
285
a8cbce97
GE
286 void close();
287
69d8da4a
GE
288 /**
289 * @brief Returns the name of the original file that will be replaced on @ref close.
290 * @retval name of the original file
291 */
ff09d317
GE
292 std::string get_original_filename()
293 { return originalfilename; }
294
69d8da4a
GE
295 /**
296 * @brief Sets the full sync mode
297 * @param do_full_sync if true the file data and metadata will be fully synced
298 * to disk on close
299 */
ff09d317
GE
300 void set_full_sync(bool do_full_sync=true)
301 { full_sync=do_full_sync; }
302
69d8da4a
GE
303 /**
304 * @brief Read the current status of the full sync mode
305 * @retval true if the full sync mode is active
306 */
ff09d317
GE
307 bool get_full_sync()
308 { return full_sync; }
309
69d8da4a
GE
310 /**
311 * @brief On @ref close the target file is assigned these permissions
312 */
313 void set_filemode_on_close(mode_t mode)
a8cbce97 314 { filemode_on_close=mode; }
ff09d317 315
69d8da4a
GE
316 /**
317 * @brief Read the permissions that will be set on @ref close
318 * @retval permissions that will be set on @ref close
319 */
320 mode_t get_filemode_on_close()
a8cbce97 321 { return filemode_on_close; }
4635af6b 322
69d8da4a 323 /**
ef2a6062
GE
324 * @brief Change file owner (chown) that will be set on @ref close
325 * @param user the new owner
326 * @param group the new group, if left empty the main group of the user is set
327 */
328 void set_owner_on_close(const I2n::User& user, const I2n::Group& group= I2n::Group())
329 {
330 UserOnClose=user;
331 GroupOnClose=group;
332 }
333
334 /**
335 * @brief Get file owner that will be set on @ref close
336 * @retval user that will be set on @ref close, an empty @ref User() means nothing will be set
337 */
338 I2n::User get_owner_on_close()
339 { return UserOnClose; }
340
341 /**
342 * @brief Get file owner group that will be set on @ref close
343 * @retval group that will be set on @ref close
344 */
345 I2n::Group get_group_on_close()
346 { return GroupOnClose; }
347
348 /**
69d8da4a
GE
349 * @brief Delete the file.
350 *
351 * calling unlink is a safe way to abort,
352 * the original file is not overwritten then
353 *
354 * @retval true if successful
355 */
356 bool unlink()
357 { return tmpfstreamTempl<Device, Tr, Alloc>::unlink(); }
ccee68fd 358
ff09d317
GE
359private:
360
69d8da4a
GE
361 /**
362 * @brief Not allowed to be called by users.
363 */
ff09d317 364 bool move(const std::string& targetpath, bool overwrite=false)
ccee68fd 365 { return tmpfstreamTempl<Device, Tr, Alloc>::move(targetpath,overwrite); }
ff09d317
GE
366};
367
69d8da4a
GE
368/**
369 * @brief ofstream which first writes to a temp file and atomically replaces an old file on close.
370 */
ff09d317 371typedef tmpfcopystreamTempl<bio::file_descriptor_sink> tmpofcopystream;
69d8da4a
GE
372/**
373 * @brief fstream which first writes to a temp file and atomically replaces an old file on close.
374 */
ff09d317
GE
375typedef tmpfcopystreamTempl<bio::file_descriptor> tmpfcopystream;
376
52d6f7fc
GE
377}
378
379#endif