Commit | Line | Data |
---|---|---|
0e23f538 TJ |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on 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 | |
42 | namespace I2n | |
43 | { | |
44 | ||
82b461e4 GE |
45 | namespace 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 |
64 | template< 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 | 73 | class tmpfstreamTempl : public bio::stream<Device, Tr, Alloc> |
52d6f7fc GE |
74 | { |
75 | private: | |
ff09d317 | 76 | std::string tmpfilename; |
0fcb8655 | 77 | bool unlinked; |
f002679a | 78 | int fd; |
52d6f7fc GE |
79 | |
80 | public: | |
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 | */ | |
140 | typedef tmpfstreamTempl<bio::file_descriptor_sink> tmpofstream; | |
141 | /** | |
142 | * @brief fstream which creates files with mkstemp | |
143 | */ | |
144 | typedef 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 |
164 | template< 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 | > > | |
173 | class tmpfcopystreamTempl : public tmpfstreamTempl<Device, Tr, Alloc> | |
174 | { | |
175 | private: | |
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 | |
182 | public: | |
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 |
364 | private: |
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 | 376 | typedef 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 |
380 | typedef tmpfcopystreamTempl<bio::file_descriptor> tmpfcopystream; |
381 | ||
52d6f7fc GE |
382 | } |
383 | ||
384 | #endif |