#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
+#include <sys/stat.h>
namespace I2n
{
namespace bio = boost::iostreams;
+/**
+ * @brief fstream or ofstream which creates files with mkstemp
+ *
+ * This class becomes an std::ostream or std::stream depending on the
+ * @ref Device used.
+ * For the most common cases, use the provided typedefs @ref tmpofstream
+ * and @ref tmpfstream.
+ * The temporary file is created with permissions 0600. These can be changed
+ * with @ref set_file_mode.
+ *
+ * @param Device Class which implements the Device Concept of boost::iostreams
+ * and offers a function Open(filedescriptor,close_on_exit). Usually
+ * this is boost::iostreams::file_descriptor and
+ * boost::iostreams::file_descriptor_sink
+ * @param Tr Character traits type
+ * @param Alloc Allocator for the character buffers
+ */
template< typename Device,
typename Tr =
BOOST_IOSTREAMS_CHAR_TRAITS(
int fd;
public:
+ /**
+ * @brief Constructs an unopened tmpfstreamTempl.
+ */
tmpfstreamTempl()
: unlinked(false), bio::stream<Device, Tr, Alloc>()
{ }
+ /**
+ * @brief Constructs and opens the tmpfstreamTempl.
+ *
+ * @param tmpnametemplate Path of the temporary file to be opened.
+ * The last 6 characters must be XXXXXX and they
+ * will be replaced with something random.
+ * @param mode std::ios_base::open_mode to open the file with
+ * @param buffer_size The size of any buffers that need to be allocated
+ * @param buffer_size The size of the putback buffer, relevant only for fstream
+ */
tmpfstreamTempl(const std::string& tmpnametemplate,
std::ios_base::open_mode mode = std::ios_base::out,
int buffer_size = -1 , int pback_size = -1)
std::ios_base::open_mode mode = std::ios_base::out,
int buffer_size = -1 , int pback_size = -1);
+ /**
+ * @brief Get the filename of the temporary file.
+ *
+ * @retval returns the filename really used with the XXXXXX replaced.
+ */
std::string get_tmp_filename()
{ return tmpfilename; }
- bool set_file_mode(int mode);
+ bool set_file_mode(mode_t mode);
bool unlink();
bool sync();
};
+
+/**
+ * @brief ofstream which creates files with mkstemp
+ */
+typedef tmpfstreamTempl<bio::file_descriptor_sink> tmpofstream;
+/**
+ * @brief fstream which creates files with mkstemp
+ */
+typedef tmpfstreamTempl<bio::file_descriptor> tmpfstream;
+
+/**
+ * @brief fstream or ofstream which first writes to a temp file and atomically
+ * replaces an old file on close.
+ *
+ * This class becomes an std::ostream or std::stream depending on the
+ * @ref Device used.
+ * For the most common cases, use the provided typedefs @ref tmpofcopystream
+ * and @ref tmpfcopystream.
+ * The temporary file is created with permissions 0600. On @ref close the
+ * permissions of the original file will be set to 0644 by default.
+ *
+ * @param Device Class which implements the Device Concept of boost::iostreams
+ * and offers a function Open(filedescriptor,close_on_exit). Usually
+ * this is boost::iostreams::file_descriptor and
+ * boost::iostreams::file_descriptor_sink
+ * @param Tr Character traits type
+ * @param Alloc Allocator for the character buffers
+ */
template< typename Device,
typename Tr =
BOOST_IOSTREAMS_CHAR_TRAITS(
private:
std::string originalfilename;
bool full_sync;
- int filemode_on_close;
+ mode_t filemode_on_close;
public:
static const std::string default_template_suffix;
static const bool default_full_sync=false;
static const int default_filemode_on_close=0644;
+ /**
+ * @brief Constructs an unopened tmpfcopystreamTempl.
+ */
tmpfcopystreamTempl()
: full_sync(default_full_sync),
filemode_on_close(default_filemode_on_close),
tmpfstreamTempl<Device, Tr, Alloc>()
{ }
+ /**
+ * @brief Constructs and opens the tmpfcopystreamTempl.
+ *
+ * The temporary file will be in the same directory with .tmp.XXXXXX appended.
+ *
+ * @param filename The original filename which will be replaced on close
+ * @param mode std::ios_base::open_mode to open the file with
+ * @param buffer_size The size of any buffers that need to be allocated
+ * @param buffer_size The size of the putback buffer, relevant only for fstream
+ */
tmpfcopystreamTempl(const std::string& filename,
std::ios_base::open_mode mode = std::ios_base::out,
int buffer_size = -1 , int pback_size = -1)
(filename+default_template_suffix,mode,buffer_size,pback_size)
{ }
+ /**
+ * @brief Constructs and opens the tmpfcopystreamTempl.
+ *
+ * filename and tmpnametemplate must be on the same filesystem.
+ *
+ * @param filename The original filename which will be replaced on close
+ * @param tmpnametemplate Path of the temporary file to be opened.
+ * The last 6 characters must be XXXXXX and they
+ * will be replaced with something random.
+ * @param mode std::ios_base::open_mode to open the file with
+ * @param buffer_size The size of any buffers that need to be allocated
+ * @param buffer_size The size of the putback buffer, relevant only for fstream
+ */
tmpfcopystreamTempl(const std::string& filename,
const std::string& tmpnametemplate,
std::ios_base::open_mode mode = std::ios_base::out,
~tmpfcopystreamTempl()
{ close(); }
+ /**
+ * @brief Opens the tmpfcopystreamTempl.
+ *
+ * The temporary file will be in the same directory with .tmp.XXXXXX appended.
+ *
+ * @param filename The original filename which will be replaced on close
+ * @param mode std::ios_base::open_mode to open the file with
+ * @param buffer_size The size of any buffers that need to be allocated
+ * @param buffer_size The size of the putback buffer, relevant only for fstream
+ * @retval true if successful
+ */
bool open(const std::string& filename,
std::ios_base::open_mode mode = std::ios_base::out,
int buffer_size = -1 , int pback_size = -1)
::open(filename+default_template_suffix,mode,buffer_size,pback_size);
}
+ /**
+ * @brief Opens the tmpfcopystreamTempl.
+ *
+ * filename and tmpnametemplate must be on the same filesystem.
+ *
+ * @param filename The original filename which will be replaced on close
+ * @param tmpnametemplate Path of the temporary file to be opened.
+ * The last 6 characters must be XXXXXX and they
+ * will be replaced with something random.
+ * @param mode std::ios_base::open_mode to open the file with
+ * @param buffer_size The size of any buffers that need to be allocated
+ * @param buffer_size The size of the putback buffer, relevant only for fstream
+ * @retval true if successful
+ */
bool open(const std::string& filename,
const std::string& tmpnametemplate,
std::ios_base::open_mode mode = std::ios_base::out,
void close();
+ /**
+ * @brief Returns the name of the original file that will be replaced on @ref close.
+ * @retval name of the original file
+ */
std::string get_original_filename()
{ return originalfilename; }
+ /**
+ * @brief Sets the full sync mode
+ * @param do_full_sync if true the file data and metadata will be fully synced
+ * to disk on close
+ */
void set_full_sync(bool do_full_sync=true)
{ full_sync=do_full_sync; }
+ /**
+ * @brief Read the current status of the full sync mode
+ * @retval true if the full sync mode is active
+ */
bool get_full_sync()
{ return full_sync; }
- void set_filemode_on_close(int mode)
+ /**
+ * @brief On @ref close the target file is assigned these permissions
+ */
+ void set_filemode_on_close(mode_t mode)
{ filemode_on_close=mode; }
- int get_filemode_on_close()
+ /**
+ * @brief Read the permissions that will be set on @ref close
+ * @retval permissions that will be set on @ref close
+ */
+ mode_t get_filemode_on_close()
{ return filemode_on_close; }
- // calling unlink is a safe way to abort,
- // the original file is not overwritten then
+ /**
+ * @brief Delete the file.
+ *
+ * calling unlink is a safe way to abort,
+ * the original file is not overwritten then
+ *
+ * @retval true if successful
+ */
+ bool unlink()
+ { return tmpfstreamTempl<Device, Tr, Alloc>::unlink(); }
private:
- // forbid users to call these functions, no need to disturbe the internals here
+ /**
+ * @brief Not allowed to be called by users.
+ */
bool move(const std::string& targetpath, bool overwrite=false)
{ return tmpfstreamTempl<Device, Tr, Alloc>::move(targetpath,overwrite); }
};
-typedef tmpfstreamTempl<bio::file_descriptor_sink> tmpofstream;
-typedef tmpfstreamTempl<bio::file_descriptor> tmpfstream;
-
+/**
+ * @brief ofstream which first writes to a temp file and atomically replaces an old file on close.
+ */
typedef tmpfcopystreamTempl<bio::file_descriptor_sink> tmpofcopystream;
+/**
+ * @brief fstream which first writes to a temp file and atomically replaces an old file on close.
+ */
typedef tmpfcopystreamTempl<bio::file_descriptor> tmpfcopystream;
}
namespace I2n
{
+/**
+* @brief opens the tmpfstreamTempl.
+*
+* @param tmpnametemplate Path of the temporary file to be opened.
+* The last 6 characters must be XXXXXX and they
+* will be replaced with something random.
+* @param mode std::ios_base::open_mode to open the file with
+* @param buffer_size The size of any buffers that need to be allocated
+* @param buffer_size The size of the putback buffer, relevant only for fstream
+* @retval true if successful
+*/
template< typename Device, typename Tr, typename Alloc >
bool tmpfstreamTempl<Device,Tr,Alloc>::open(const std::string& tmpnametemplate,
std::ios_base::open_mode mode,
if (fd==-1)
return false;
- boost::iostreams::stream<Device,Tr,Alloc>::open(Device(fd,true));
+ boost::iostreams::stream<Device,Tr,Alloc>::open(Device(fd,true),
+ buffer_size,pback_size);
return tmpfstreamTempl<Device,Tr,Alloc>::is_open();
}
+/**
+* @brief Changes permissions (chmod) of the file.
+*
+* @param mode the new mode as in chmod
+*/
template< typename Device, typename Tr, typename Alloc >
-bool tmpfstreamTempl<Device,Tr,Alloc>::set_file_mode(int mode)
+bool tmpfstreamTempl<Device,Tr,Alloc>::set_file_mode(mode_t mode)
{
if (!get_tmp_filename().empty() && !is_unlinked())
return I2n::chmod(get_tmp_filename(),mode);
return false;
}
+/**
+* @brief Delete the file.
+*
+* Can be called while the file is still open.
+*
+* @retval true if successful
+*/
template< typename Device, typename Tr, typename Alloc >
bool tmpfstreamTempl<Device,Tr,Alloc>::unlink()
{
return false;
}
+/**
+* @brief Move the file to another name or path.
+*
+* The temporary file and the target path must be on the same filesystem.
+* Afterwards all operations (e.g. @ref unlink) are on the new filename.
+*
+* @param targetpath name and path of the new filename
+* @param overwrite overwrite an already existing targetpath or not
+* @retval true if successful
+*/
template< typename Device, typename Tr, typename Alloc >
bool tmpfstreamTempl<Device,Tr,Alloc>::move(const std::string& targetpath,
bool overwrite)
return success;
}
+/**
+* @brief Sync the data and metadata of the file to disk.
+*
+* @retval true if successful
+*/
template< typename Device, typename Tr, typename Alloc >
bool tmpfstreamTempl<Device,Tr,Alloc>::sync()
{
return dirsync(dirname(get_tmp_filename()));
}
+/**
+* @brief Close the stream and atomically overwrite an existing original file.
+*/
template< typename Device, typename Tr, typename Alloc >
void tmpfcopystreamTempl<Device,Tr,Alloc>::close()
{