/
fs_commit.hpp
97 lines (82 loc) · 2.63 KB
/
fs_commit.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
Copyright (C) 2016 by Ignacio R. Morelle <shadowm2006@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Atomic filesystem commit functions.
*/
#ifndef CAMPAIGN_SERVER_FS_COMMIT_HPP_INCLUDED
#define CAMPAIGN_SERVER_FS_COMMIT_HPP_INCLUDED
#include "filesystem.hpp"
#include <boost/noncopyable.hpp>
class config;
namespace filesystem
{
/**
* Wrapper class that guarantees that file commit atomicity.
*
* It is possible for a signal or exception to cause a file write to be aborted
* in the middle of the process, leaving potentially inconsistent contents
* behind which may be read by the same or another application later and result
* in errors or further data loss.
*
* This wrapper prevents this by providing callers with an interface to request
* a write stream that will be actually associated to a temporary file. Once
* the caller is done with the file, it should call the commit() method to
* complete the process so that the temporary replaces the original in an
* atomic step.
*
* The rationale for using an explicit commit() method instead of the class
* destructor is that the destructor will also be invoked during exception
* handling, which could still cause the destination file to end up in an
* inconsistent state.
*
* Note that if the destructor is invoked before commit() is, the temporary
* file will be left behind. This is deliberate so as to provide a way for
* the user to look at the resulting file and optionally try to reconcile it
* against the original.
*/
class atomic_commit : private boost::noncopyable
{
public:
/**
* Constructor.
*
* @throws filesystem::io_exception if the operation fails in some way.
*/
atomic_commit(const std::string& filename);
~atomic_commit();
/**
* Returns the write stream associated with the file.
*
* Before commit() is invoked, this refers to the temporary file; afterwards,
* to the destination.
*/
scoped_ostream& ostream()
{
return out_;
}
/**
* Commits the new file contents to disk atomically.
*
* @throws filesystem::io_exception if the operation fails in some way.
*/
void commit();
private:
std::string temp_name_;
std::string dest_name_;
scoped_ostream out_;
#ifndef _WIN32
int outfd_;
#endif
};
}
#endif