add ISO-8601 formatters to timefunc
[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()
5a354dce
TJ
85 : bio::stream<Device, Tr, Alloc>()
86 , unlinked(false)
87 , fd(-1)
52d6f7fc
GE
88 { }
89
69d8da4a
GE
90 /**
91 * @brief Constructs and opens the tmpfstreamTempl.
92 *
93 * @param tmpnametemplate Path of the temporary file to be opened.
94 * The last 6 characters must be XXXXXX and they
95 * will be replaced with something random.
96 * @param mode std::ios_base::open_mode to open the file with
97 * @param buffer_size The size of any buffers that need to be allocated
98 * @param buffer_size The size of the putback buffer, relevant only for fstream
99 */
82b461e4 100 tmpfstreamTempl(const std::string& tmpnametemplate,
52d6f7fc
GE
101 std::ios_base::open_mode mode = std::ios_base::out,
102 int buffer_size = -1 , int pback_size = -1)
5a354dce
TJ
103 : bio::stream<Device, Tr, Alloc>()
104 , unlinked(false)
105 , fd(-1)
52d6f7fc
GE
106 {
107 open(tmpnametemplate,mode,buffer_size,pback_size);
108 }
109
110 bool open(const std::string& tmpnametemplate,
111 std::ios_base::open_mode mode = std::ios_base::out,
82b461e4 112 int buffer_size = -1 , int pback_size = -1);
52d6f7fc 113
69d8da4a
GE
114 /**
115 * @brief Get the filename of the temporary file.
116 *
117 * @retval returns the filename really used with the XXXXXX replaced.
118 */
52d6f7fc 119 std::string get_tmp_filename()
ff09d317 120 { return tmpfilename; }
52d6f7fc 121
69d8da4a 122 bool set_file_mode(mode_t mode);
52d6f7fc 123
ef2a6062
GE
124 bool set_owner(const I2n::User& user, const I2n::Group& group= I2n::Group());
125
82b461e4 126 bool unlink();
52d6f7fc 127
0fcb8655
GE
128 bool is_unlinked()
129 { return unlinked; }
130
131 bool move(const std::string& targetpath, bool overwrite=false);
f002679a
GE
132
133 bool sync();
52d6f7fc
GE
134};
135
69d8da4a
GE
136
137/**
138 * @brief ofstream which creates files with mkstemp
139 */
140typedef tmpfstreamTempl<bio::file_descriptor_sink> tmpofstream;
141/**
142 * @brief fstream which creates files with mkstemp
143 */
144typedef tmpfstreamTempl<bio::file_descriptor> tmpfstream;
145
146/**
147 * @brief fstream or ofstream which first writes to a temp file and atomically
148 * replaces an old file on close.
149 *
150 * This class becomes an std::ostream or std::stream depending on the
151 * @ref Device used.
152 * For the most common cases, use the provided typedefs @ref tmpofcopystream
153 * and @ref tmpfcopystream.
154 * The temporary file is created with permissions 0600. On @ref close the
155 * permissions of the original file will be set to 0644 by default.
156 *
157 * @param Device Class which implements the Device Concept of boost::iostreams
158 * and offers a function Open(filedescriptor,close_on_exit). Usually
159 * this is boost::iostreams::file_descriptor and
160 * boost::iostreams::file_descriptor_sink
161 * @param Tr Character traits type
162 * @param Alloc Allocator for the character buffers
163 */
ff09d317
GE
164template< typename Device,
165 typename Tr =
166 BOOST_IOSTREAMS_CHAR_TRAITS(
167 BOOST_DEDUCED_TYPENAME bio::char_type_of<Device>::type
168 ),
169 typename Alloc =
170 std::allocator<
171 BOOST_DEDUCED_TYPENAME bio::char_type_of<Device>::type
172 > >
173class tmpfcopystreamTempl : public tmpfstreamTempl<Device, Tr, Alloc>
174{
175private:
176 std::string originalfilename;
177 bool full_sync;
69d8da4a 178 mode_t filemode_on_close;
ef2a6062
GE
179 I2n::User UserOnClose;
180 I2n::Group GroupOnClose;
ff09d317
GE
181
182public:
183 static const std::string default_template_suffix;
a8cbce97
GE
184 static const bool default_full_sync=false;
185 static const int default_filemode_on_close=0644;
ff09d317 186
69d8da4a
GE
187 /**
188 * @brief Constructs an unopened tmpfcopystreamTempl.
189 */
ff09d317 190 tmpfcopystreamTempl()
5a354dce
TJ
191 : tmpfstreamTempl<Device, Tr, Alloc>()
192 , full_sync(default_full_sync)
193 , filemode_on_close(default_filemode_on_close)
194 , UserOnClose()
195 , GroupOnClose()
ff09d317
GE
196 { }
197
69d8da4a
GE
198 /**
199 * @brief Constructs and opens the tmpfcopystreamTempl.
200 *
201 * The temporary file will be in the same directory with .tmp.XXXXXX appended.
202 *
203 * @param filename The original filename which will be replaced on close
204 * @param mode std::ios_base::open_mode to open the file with
205 * @param buffer_size The size of any buffers that need to be allocated
206 * @param buffer_size The size of the putback buffer, relevant only for fstream
207 */
ff09d317
GE
208 tmpfcopystreamTempl(const std::string& filename,
209 std::ios_base::open_mode mode = std::ios_base::out,
210 int buffer_size = -1 , int pback_size = -1)
5a354dce
TJ
211 : tmpfstreamTempl<Device, Tr, Alloc>(filename+default_template_suffix,mode,buffer_size,pback_size)
212 , originalfilename(filename)
213 , full_sync(default_full_sync)
214 , filemode_on_close(default_filemode_on_close)
215 , UserOnClose()
216 , GroupOnClose()
ff09d317
GE
217 { }
218
69d8da4a
GE
219 /**
220 * @brief Constructs and opens the tmpfcopystreamTempl.
221 *
222 * filename and tmpnametemplate must be on the same filesystem.
223 *
224 * @param filename The original filename which will be replaced on close
225 * @param tmpnametemplate Path of the temporary file to be opened.
226 * The last 6 characters must be XXXXXX and they
227 * will be replaced with something random.
228 * @param mode std::ios_base::open_mode to open the file with
229 * @param buffer_size The size of any buffers that need to be allocated
230 * @param buffer_size The size of the putback buffer, relevant only for fstream
231 */
ff09d317
GE
232 tmpfcopystreamTempl(const std::string& filename,
233 const std::string& tmpnametemplate,
234 std::ios_base::open_mode mode = std::ios_base::out,
235 int buffer_size = -1 , int pback_size = -1)
5a354dce
TJ
236 : tmpfstreamTempl<Device, Tr, Alloc>(tmpnametemplate,mode,buffer_size,pback_size)
237 , originalfilename(filename)
238 , full_sync(default_full_sync)
239 , filemode_on_close(default_filemode_on_close)
240 , UserOnClose()
241 , GroupOnClose()
ff09d317
GE
242 { }
243
ccee68fd
GE
244 ~tmpfcopystreamTempl()
245 { close(); }
246
69d8da4a
GE
247 /**
248 * @brief Opens the tmpfcopystreamTempl.
249 *
250 * The temporary file will be in the same directory with .tmp.XXXXXX appended.
251 *
252 * @param filename The original filename which will be replaced on close
253 * @param mode std::ios_base::open_mode to open the file with
254 * @param buffer_size The size of any buffers that need to be allocated
255 * @param buffer_size The size of the putback buffer, relevant only for fstream
256 * @retval true if successful
257 */
ff09d317
GE
258 bool open(const std::string& filename,
259 std::ios_base::open_mode mode = std::ios_base::out,
260 int buffer_size = -1 , int pback_size = -1)
261 {
262 originalfilename=filename;
263 return tmpfstreamTempl<Device, Tr, Alloc>
264 ::open(filename+default_template_suffix,mode,buffer_size,pback_size);
265 }
266
69d8da4a
GE
267 /**
268 * @brief Opens the tmpfcopystreamTempl.
269 *
270 * filename and tmpnametemplate must be on the same filesystem.
271 *
272 * @param filename The original filename which will be replaced on close
273 * @param tmpnametemplate Path of the temporary file to be opened.
274 * The last 6 characters must be XXXXXX and they
275 * will be replaced with something random.
276 * @param mode std::ios_base::open_mode to open the file with
277 * @param buffer_size The size of any buffers that need to be allocated
278 * @param buffer_size The size of the putback buffer, relevant only for fstream
279 * @retval true if successful
280 */
ff09d317
GE
281 bool open(const std::string& filename,
282 const std::string& tmpnametemplate,
283 std::ios_base::open_mode mode = std::ios_base::out,
284 int buffer_size = -1 , int pback_size = -1)
285 {
286 originalfilename=filename;
287 return tmpfstreamTempl<Device, Tr, Alloc>
288 ::open(tmpnametemplate,mode,buffer_size,pback_size);
289 }
290
a8cbce97
GE
291 void close();
292
69d8da4a
GE
293 /**
294 * @brief Returns the name of the original file that will be replaced on @ref close.
295 * @retval name of the original file
296 */
ff09d317
GE
297 std::string get_original_filename()
298 { return originalfilename; }
299
69d8da4a
GE
300 /**
301 * @brief Sets the full sync mode
302 * @param do_full_sync if true the file data and metadata will be fully synced
303 * to disk on close
304 */
ff09d317
GE
305 void set_full_sync(bool do_full_sync=true)
306 { full_sync=do_full_sync; }
307
69d8da4a
GE
308 /**
309 * @brief Read the current status of the full sync mode
310 * @retval true if the full sync mode is active
311 */
ff09d317
GE
312 bool get_full_sync()
313 { return full_sync; }
314
69d8da4a
GE
315 /**
316 * @brief On @ref close the target file is assigned these permissions
317 */
318 void set_filemode_on_close(mode_t mode)
a8cbce97 319 { filemode_on_close=mode; }
ff09d317 320
69d8da4a
GE
321 /**
322 * @brief Read the permissions that will be set on @ref close
323 * @retval permissions that will be set on @ref close
324 */
325 mode_t get_filemode_on_close()
a8cbce97 326 { return filemode_on_close; }
4635af6b 327
69d8da4a 328 /**
ef2a6062
GE
329 * @brief Change file owner (chown) that will be set on @ref close
330 * @param user the new owner
331 * @param group the new group, if left empty the main group of the user is set
332 */
333 void set_owner_on_close(const I2n::User& user, const I2n::Group& group= I2n::Group())
334 {
335 UserOnClose=user;
336 GroupOnClose=group;
337 }
338
339 /**
340 * @brief Get file owner that will be set on @ref close
341 * @retval user that will be set on @ref close, an empty @ref User() means nothing will be set
342 */
343 I2n::User get_owner_on_close()
344 { return UserOnClose; }
345
346 /**
347 * @brief Get file owner group that will be set on @ref close
348 * @retval group that will be set on @ref close
349 */
350 I2n::Group get_group_on_close()
351 { return GroupOnClose; }
352
353 /**
69d8da4a
GE
354 * @brief Delete the file.
355 *
356 * calling unlink is a safe way to abort,
357 * the original file is not overwritten then
358 *
359 * @retval true if successful
360 */
361 bool unlink()
362 { return tmpfstreamTempl<Device, Tr, Alloc>::unlink(); }
ccee68fd 363
ff09d317
GE
364private:
365
69d8da4a
GE
366 /**
367 * @brief Not allowed to be called by users.
368 */
ff09d317 369 bool move(const std::string& targetpath, bool overwrite=false)
ccee68fd 370 { return tmpfstreamTempl<Device, Tr, Alloc>::move(targetpath,overwrite); }
ff09d317
GE
371};
372
69d8da4a
GE
373/**
374 * @brief ofstream which first writes to a temp file and atomically replaces an old file on close.
375 */
ff09d317 376typedef tmpfcopystreamTempl<bio::file_descriptor_sink> tmpofcopystream;
69d8da4a
GE
377/**
378 * @brief fstream which first writes to a temp file and atomically replaces an old file on close.
379 */
ff09d317
GE
380typedef tmpfcopystreamTempl<bio::file_descriptor> tmpfcopystream;
381
52d6f7fc
GE
382}
383
384#endif