-
Notifications
You must be signed in to change notification settings - Fork 5
/
sequential_file_writer.cc
83 lines (69 loc) · 2.18 KB
/
sequential_file_writer.cc
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
#include <iostream>
#include <utility>
#include <stdexcept>
#include <cstdio>
#include <sstream>
#include <sys/errno.h>
#include "utils.h"
#include "sequential_file_writer.h"
SequentialFileWriter::SequentialFileWriter()
: m_no_space(false)
{
}
SequentialFileWriter::SequentialFileWriter(SequentialFileWriter&&) = default;
SequentialFileWriter& SequentialFileWriter::operator=(SequentialFileWriter&&) = default;
// Currently the implementation is very simple using standard library facilities. More advanced implementations
// allowing for better parallelism are possible, e.g. using aio_write().
void SequentialFileWriter::OpenIfNecessary(const std::string& name)
{
// FIXME: Sanitise file names. Currently there's nothing preventing the user from giving absolute paths,
// Paths with .. etc. We should accept simple relative paths only.
if (m_ofs.is_open()) {
return;
}
using std::ios_base;
std::ofstream ofs;
ofs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// TODO: If the given relative path has a directory component, create it.
ofs.open(name, ios_base::out | ios_base::trunc | ios_base::binary);
}
catch (const std::system_error& ex) {
RaiseError("opening", ex);
}
m_ofs = std::move(ofs);
m_name = name;
m_no_space = false;
return;
}
void SequentialFileWriter::Write(std::string& data)
{
try {
m_ofs << data;
}
catch (const std::system_error& ex) {
if (m_ofs.is_open()) {
m_ofs.close();
}
std::remove(m_name.c_str()); // Best effort. We expect it to succeed, but we don't check whether it did
RaiseError("writing to", ex);
}
data.clear();
return;
}
void SequentialFileWriter::RaiseError(const std::string action_attempted, const std::system_error& ex)
{
const int ec = ex.code().value();
switch (ec) {
case ENOSPC:
case EFBIG:
m_no_space = true;
break;
// TODO: Also handle permission errors.
default:
break;
}
std::ostringstream sts;
sts << "Error " << action_attempted << " the file " << m_name << ": ";
raise_from_system_error_code(sts.str(), ec);
}