-
Notifications
You must be signed in to change notification settings - Fork 1
/
temp-file.cpp
111 lines (94 loc) · 3.48 KB
/
temp-file.cpp
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
98
99
100
101
102
103
104
105
106
107
108
109
110
#include "temp-file.h"
#include "util.h"
#include "tm.h"
#include "xerror.h"
#include <unistd.h>
#include <rang.hpp>
#include <boost/format.hpp>
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>
#include <cstdio>
#include <iterator>
#include <stdexcept>
//#include <experimental/filesystem>
static std::string dirLocation = "."; // where these files are created /tmp breaks std::rename below (cross-device error)
static const char *deftExt = "tmp"; // default file extension
static unsigned sno = 0; // serial number of the file (XXX thread unsafe)
static bool ctlParamKeepFiles = false;
class TempFile__KeptFileRegistry : public std::vector<std::string> {
public:
TempFile__KeptFileRegistry() { }
~TempFile__KeptFileRegistry() {
if (!empty()) {
std::ostringstream ssRmShellFileName;
ssRmShellFileName << "temp-files-to-remove-" << Tm::strYearToMicrosecond() << ".sh";
std::ofstream rmShellFile(ssRmShellFileName.str(), std::ios::trunc);
rmShellFile << "#!/bin/sh" << std::endl;
rmShellFile << std::endl;
for (auto f : *this)
rmShellFile << "rm " << f << std::endl;
rmShellFile.close();
std::cout << rang::fg::yellow << "Some TempFile objects weren't removed from disk (" << size() << " of them),"
<< " please run the script to remove them: " << ssRmShellFileName.str()
<< rang::style::reset << std::endl;
}
}
}; // TempFile__KeptFileRegistry
static TempFile__KeptFileRegistry keptFileRegistry;
TempFile::TempFile(const std::string &ext, const std::string &content)
: fullPath(genName(ext)),
madePermanent(false)
{
if (!content.empty())
std::ofstream(fullPath, std::ios::out) << content;
}
TempFile::TempFile(const std::string &ext, const Binary *content)
: fullPath(genName(ext)),
madePermanent(false)
{
std::ofstream fout(fullPath, std::ios::out);
fout.write((char*)&(*content)[0], content->size());
}
TempFile::~TempFile() {
if (!madePermanent) {
// the file may or may not exist
if (!ctlParamKeepFiles)
(void)std::remove(fullPath.c_str()); // ignore the error code
else
keptFileRegistry.push_back(fullPath);
}
}
std::vector<uint8_t>* TempFile::toBinary() const {
std::ifstream file(fullPath, std::ios::binary);
return new std::vector<uint8_t>(std::istreambuf_iterator<char>{file}, {});
}
void TempFile::toPermanent(const std::string &permFileName) const {
if (madePermanent)
ERROR("temp-file can only be made permanent once!")
// fails with cross-device error when tmp files are on /tmp
if (std::rename(fullPath.c_str(), permFileName.c_str()) != 0)
throw std::runtime_error("rename() failed!");
madePermanent = true;
// not available on FreeBSD: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=235749
//std::experimental::filesystem::copy(fullPath, permFileName);
}
void TempFile::setCtlParam(const std::vector<std::string> &name, const std::string &value) {
if (name.size() != 1)
ERROR("TempFile::setCtlParam: name should have just one part")
if (name[0] == "keep-files")
ctlParamKeepFiles = Util::strAsBool(value);
else
ERROR("TempFile::setCtlParam: unknown parameter '" << name[0] << "'")
}
/// intenals
std::string TempFile::genName(const std::string &ext) {
return str(boost::format("%1%/%2%-pid%3%-sno%4%.%5%") %
dirLocation %
PROGRAM_NAME %
::getpid() %
++sno %
(ext.empty() ? deftExt : ext.c_str()));
}