2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
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.
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.
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.
21 * @brief fstream which creates files with mkstemp.
23 * @note This file contains the template implementation. You only need
24 * to include it if you use something else than the explicitly
25 * instantiated and typedefed versions
27 * @author Gerd v. Egidy
29 * @copyright © Copyright 2010 by Intra2net AG
32 #ifndef __I2N_TMPFSTREAM_IMPL_HPP__
33 #define __I2N_TMPFSTREAM_IMPL_HPP__
38 #include <sys/types.h>
45 #include <tmpfstream.hpp>
46 #include <filefunc.hxx>
53 * @brief opens the tmpfstreamTempl.
55 * @param tmpnametemplate Path of the temporary file to be opened.
56 * The last 6 characters must be XXXXXX and they
57 * will be replaced with something random.
58 * @param mode std::ios_base::open_mode to open the file with
59 * @param buffer_size The size of any buffers that need to be allocated
60 * @param buffer_size The size of the putback buffer, relevant only for fstream
61 * @retval true if successful
63 template< typename Device, typename Tr, typename Alloc >
64 bool tmpfstreamTempl<Device,Tr,Alloc>::open(const std::string& tmpnametemplate,
65 std::ios_base::open_mode mode,
66 int buffer_size, int pback_size)
68 if (tmpfstreamTempl<Device,Tr,Alloc>::is_open())
69 tmpfstreamTempl<Device,Tr,Alloc>::close();
71 char* chbuf=new char[tmpnametemplate.size()+1];
72 tmpnametemplate.copy(chbuf,tmpnametemplate.size()+1);
73 chbuf[tmpnametemplate.size()]=0;
75 // always assume out-mode, otherwise the tmpfstream would be useless
77 if (mode & std::ios_base::in)
82 if (mode & std::ios_base::app)
85 fd=mkostemp(chbuf,flags);
92 boost::iostreams::stream<Device,Tr,Alloc>::open(Device(fd, boost::iostreams::close_handle),
93 buffer_size,pback_size);
95 return tmpfstreamTempl<Device,Tr,Alloc>::is_open();
99 * @brief Changes permissions (chmod) of the file.
101 * @param mode the new mode as in chmod
102 * @retval true if successful
104 template< typename Device, typename Tr, typename Alloc >
105 bool tmpfstreamTempl<Device,Tr,Alloc>::set_file_mode(mode_t mode)
107 if (!get_tmp_filename().empty() && !is_unlinked())
108 return I2n::chmod(get_tmp_filename(),mode);
114 * @brief Changes the owner of the file (chown).
116 * @param user the new owner
117 * @param group the new group, if left empty the main group of the user is set
118 * @retval true if successful
120 template< typename Device, typename Tr, typename Alloc >
121 bool tmpfstreamTempl<Device,Tr,Alloc>::set_owner(const I2n::User& user, const I2n::Group& group)
123 if (!get_tmp_filename().empty() && !is_unlinked())
124 return I2n::chown(get_tmp_filename(),user,group);
130 * @brief Delete the file.
132 * Can be called while the file is still open.
134 * @retval true if successful
136 template< typename Device, typename Tr, typename Alloc >
137 bool tmpfstreamTempl<Device,Tr,Alloc>::unlink()
139 if (!get_tmp_filename().empty())
141 if (I2n::unlink(get_tmp_filename()))
154 * @brief Move the file to another name or path.
156 * The temporary file and the target path must be on the same filesystem.
157 * Afterwards all operations (e.g. @ref unlink) are on the new filename.
159 * @param targetpath name and path of the new filename
160 * @param overwrite overwrite an already existing targetpath or not
161 * @retval true if successful
163 template< typename Device, typename Tr, typename Alloc >
164 bool tmpfstreamTempl<Device,Tr,Alloc>::move(const std::string& targetpath,
167 if (get_tmp_filename().empty() || is_unlinked())
174 // this overwrites an already existing target without further warning
175 // other errors possible, see errno
176 if (::rename( get_tmp_filename().c_str(), targetpath.c_str() ) == 0)
181 // fails if the target already exists
182 // other errors possible, see errno
183 if (::link( get_tmp_filename().c_str(), targetpath.c_str() ) == 0)
186 ::unlink(get_tmp_filename().c_str());
192 // store tmpfilename to allow double-move
193 tmpfilename=targetpath;
200 * @brief Sync the data and metadata of the file to disk.
202 * @retval true if successful
204 template< typename Device, typename Tr, typename Alloc >
205 bool tmpfstreamTempl<Device,Tr,Alloc>::sync()
207 if (!tmpfstreamTempl<Device,Tr,Alloc>::is_open())
210 tmpfstreamTempl<Device,Tr,Alloc>::flush();
212 // sync the file itself
216 // sync the dir: both is needed for data + metadata sync
217 return dirsync(dirname(get_tmp_filename()));
221 * @brief Close the stream and atomically overwrite an existing original file.
223 template< typename Device, typename Tr, typename Alloc >
224 void tmpfcopystreamTempl<Device,Tr,Alloc>::close()
226 if (!tmpfstreamTempl<Device,Tr,Alloc>::is_open() ||
227 tmpfstreamTempl<Device,Tr,Alloc>::is_unlinked())
231 tmpfstreamTempl<Device,Tr,Alloc>::sync();
233 // close the underlying filedescriptor
234 tmpfstreamTempl<Device,Tr,Alloc>::close();
236 tmpfstreamTempl<Device,Tr,Alloc>::set_file_mode(filemode_on_close);
238 if (UserOnClose != I2n::User())
239 tmpfstreamTempl<Device,Tr,Alloc>::set_owner(UserOnClose,GroupOnClose);
241 move(get_original_filename(),true);
244 dirsync(dirname(get_original_filename()));