-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathTargetFile.cpp
More file actions
79 lines (67 loc) · 2.35 KB
/
TargetFile.cpp
File metadata and controls
79 lines (67 loc) · 2.35 KB
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
#include "swift/extractor/infra/file/TargetFile.h"
#include "swift/extractor/infra/file/FsLogger.h"
#include "swift/logging/SwiftLogging.h"
#include "swift/logging/SwiftAssert.h"
#include <cassert>
#include <cstdio>
#include <cerrno>
#include <system_error>
#include <filesystem>
namespace fs = std::filesystem;
namespace codeql {
using namespace fs_logger;
namespace {
std::error_code currentErrorCode() {
return {errno, std::system_category()};
}
void ensureParentDir(const fs::path& path) {
auto parent = path.parent_path();
std::error_code ec;
fs::create_directories(parent, ec);
CODEQL_ASSERT(!ec, "Unable to create directory {} ({})", parent, ec);
}
fs::path initPath(const std::filesystem::path& target, const std::filesystem::path& dir) {
fs::path ret{dir};
CODEQL_ASSERT(!target.empty());
ret /= target.relative_path();
ensureParentDir(ret);
return ret;
}
} // namespace
TargetFile::TargetFile(const std::filesystem::path& target,
const std::filesystem::path& targetDir,
const std::filesystem::path& workingDir)
: workingPath{initPath(target, workingDir)}, targetPath{initPath(target, targetDir)} {}
bool TargetFile::init() {
errno = 0;
// since C++17 "x" mode opens with O_EXCL (fails if file already exists)
if (auto f = std::fopen(targetPath.c_str(), "wx")) {
std::fclose(f);
out.open(workingPath);
checkOutput("open");
return true;
}
CODEQL_ASSERT(errno == EEXIST, "Unable to open {} for writing ({})", targetPath,
currentErrorCode());
// else the file already exists and we just lost the race
return false;
}
std::optional<TargetFile> TargetFile::create(const std::filesystem::path& target,
const std::filesystem::path& targetDir,
const std::filesystem::path& workingDir) {
TargetFile ret{target, targetDir, workingDir};
if (ret.init()) return ret;
return std::nullopt;
}
void TargetFile::commit() {
if (out.is_open()) {
out.close();
std::error_code ec;
fs::rename(workingPath, targetPath, ec);
CODEQL_ASSERT(!ec, "Unable to rename {} -> {} ({})", workingPath, targetPath, ec);
}
}
void TargetFile::checkOutput(const char* action) {
CODEQL_ASSERT(out, "Unable to {} {} ({})", action, workingPath, currentErrorCode());
}
} // namespace codeql