struct FindCoverageFileResult
{
bool found;
- std::string path;
+ fs::path path;
bool mangled;
};
// (in CWD) if -fprofile-dir=DIR is present (regardless of DIR) instead of the
// traditional /dir/to/example.gcno.
- std::string mangled_form = core::Result::gcno_file_in_mangled_form(ctx);
- std::string unmangled_form = core::Result::gcno_file_in_unmangled_form(ctx);
- std::string found_file;
+ fs::path mangled_form = core::Result::gcno_file_in_mangled_form(ctx);
+ fs::path unmangled_form = core::Result::gcno_file_in_unmangled_form(ctx);
+ fs::path found_file;
if (DirEntry(mangled_form).is_regular_file()) {
LOG("Found coverage file {}", mangled_form);
found_file = mangled_form;
// Call `config_line_handler` for each line in `path`.
bool
-parse_config_file(const std::string& path,
+parse_config_file(const fs::path& path,
const ConfigLineHandler& config_line_handler)
{
- std::ifstream file(path);
+ std::ifstream file(util::pstr(path).c_str());
if (!file) {
return false;
}
Config::update_from_file(const fs::path& path)
{
return parse_config_file(
- util::pstr(path),
- [&](const auto& /*line*/, const auto& key, const auto& value) {
+ path, [&](const auto& /*line*/, const auto& key, const auto& value) {
if (!key.empty()) {
set_item(key, value, std::nullopt, false, util::pstr(path));
}
}
static tl::expected<util::Bytes, std::string>
-read_from_path_or_stdin(const std::string& path)
+read_from_path_or_stdin(const fs::path& path)
{
if (path == "-") {
return util::read_fd(STDIN_FILENO).transform_error([&](auto error) {
}
static int
-inspect_path(const std::string& path)
+inspect_path(const fs::path& path)
{
std::optional<util::DirEntry> orig_dir_entry;
if (path != "-") {
return k_unknown_file_type;
}
-std::string
+fs::path
gcno_file_in_mangled_form(const Context& ctx)
{
const auto& output_obj = ctx.args_info.output_obj;
- const std::string abs_output_obj =
- output_obj.is_absolute() ? util::pstr(output_obj)
- : FMT("{}/{}", ctx.apparent_cwd, output_obj);
- std::string hashified_obj = abs_output_obj;
+ std::string hashified_obj = (ctx.apparent_cwd / output_obj).generic_string();
std::replace(hashified_obj.begin(), hashified_obj.end(), '/', '#');
- return util::pstr(util::with_extension(hashified_obj, ".gcno"));
+ return util::with_extension(hashified_obj, ".gcno");
}
-std::string
+fs::path
gcno_file_in_unmangled_form(const Context& ctx)
{
- return util::pstr(util::with_extension(ctx.args_info.output_obj, ".gcno"));
+ return util::with_extension(ctx.args_info.output_obj, ".gcno");
}
Deserializer::Deserializer(nonstd::span<const uint8_t> data) : m_data(data)
const char* file_type_to_string(FileType type);
-std::string gcno_file_in_mangled_form(const Context& ctx);
-std::string gcno_file_in_unmangled_form(const Context& ctx);
+std::filesystem::path gcno_file_in_mangled_form(const Context& ctx);
+std::filesystem::path gcno_file_in_unmangled_form(const Context& ctx);
// This class knows how to deserializer a result cache entry.
class Deserializer
#include <ccache/util/direntry.hpp>
#include <ccache/util/expected.hpp>
#include <ccache/util/file.hpp>
+#include <ccache/util/filesystem.hpp>
#include <ccache/util/format.hpp>
#include <ccache/util/wincompat.hpp>
#include <vector>
+namespace fs = util::filesystem;
+
using util::DirEntry;
namespace core {
ResultExtractor::ResultExtractor(
- const std::string& output_directory,
+ const fs::path& output_directory,
std::optional<GetRawFilePathFunction> get_raw_file_path)
: m_output_directory(output_directory),
m_get_raw_file_path(get_raw_file_path)
suffix.resize(suffix.length() - 1);
}
- const auto dest_path = FMT("{}/ccache-result{}", m_output_directory, suffix);
+ const auto dest_path = m_output_directory / FMT("ccache-result{}", suffix);
util::throw_on_error<Error>(util::write_file(dest_path, data),
FMT("Failed to write to {}: ", dest_path));
}
#include <nonstd/span.hpp>
#include <cstdint>
+#include <filesystem>
#include <functional>
#include <optional>
#include <string>
class ResultExtractor : public Result::Deserializer::Visitor
{
public:
- using GetRawFilePathFunction = std::function<std::string(uint8_t)>;
+ using GetRawFilePathFunction = std::function<std::filesystem::path(uint8_t)>;
//`result_path` should be the path to the local result entry file if the
// result comes from local storage.
ResultExtractor(
- const std::string& output_directory,
+ const std::filesystem::path& output_directory,
std::optional<GetRawFilePathFunction> get_raw_file_path = std::nullopt);
void on_embedded_file(uint8_t file_number,
uint64_t file_size) override;
private:
- std::string m_output_directory;
+ std::filesystem::path m_output_directory;
std::optional<GetRawFilePathFunction> m_get_raw_file_path;
};
#include <ccache/util/fd.hpp>
#include <ccache/util/file.hpp>
+#include <ccache/util/filesystem.hpp>
#include <ccache/util/format.hpp>
#include <ccache/util/logging.hpp>
#include <ccache/util/string.hpp>
# include <unistd.h>
#endif
+namespace fs = util::filesystem;
+
const uint8_t HASH_DELIMITER[] = {0, 'c', 'C', 'a', 'C', 'h', 'E', 0};
Hash::Hash()
}
tl::expected<void, std::string>
-Hash::hash_file(const std::string& path)
+Hash::hash_file(const fs::path& path)
{
- util::Fd fd(open(path.c_str(), O_RDONLY | O_BINARY));
+ util::Fd fd(open(util::pstr(path).c_str(), O_RDONLY | O_BINARY));
if (!fd) {
LOG("Failed to open {}: {}", path, strerror(errno));
return tl::unexpected(strerror(errno));
//
// If hash debugging is enabled, the data is written verbatim to the text
// input file.
- tl::expected<void, std::string> hash_file(const std::string& path);
+ tl::expected<void, std::string> hash_file(const std::filesystem::path& path);
// Add contents read from an open file descriptor to the hash.
//
};
bool
-InodeCache::mmap_file(const std::string& inode_cache_file)
+InodeCache::mmap_file(const std::filesystem::path& path)
{
m_sr = nullptr;
m_map.unmap();
- m_fd = util::Fd(open(inode_cache_file.c_str(), O_RDWR));
+ m_fd = util::Fd(open(util::pstr(path).c_str(), O_RDWR));
if (!m_fd) {
- LOG("Failed to open inode cache {}: {}", inode_cache_file, strerror(errno));
+ LOG("Failed to open inode cache {}: {}", path, strerror(errno));
return false;
}
if (!fd_is_on_known_to_work_file_system(*m_fd)) {
auto map = util::MemoryMap::map(*m_fd, sizeof(SharedRegion));
if (!map) {
- LOG("Failed to map inode cache file {}: {}", inode_cache_file, map.error());
+ LOG("Failed to map inode cache file {}: {}", path, map.error());
return false;
}
k_version);
map->unmap();
m_fd.close();
- unlink(inode_cache_file.c_str());
+ fs::remove(path);
return false;
}
m_map = std::move(*map);
m_sr = sr;
if (m_config.debug()) {
- LOG("Inode cache file loaded: {}", inode_cache_file);
+ LOG("Inode cache file loaded: {}", path);
}
return true;
}
}
bool
-InodeCache::create_new_file(const std::string& filename)
+InodeCache::create_new_file(const fs::path& path)
{
// Create the new file to a temporary name to prevent other processes from
// mapping it before it is fully initialized.
- auto tmp_file = util::TemporaryFile::create(filename);
+ auto tmp_file = util::TemporaryFile::create(path);
if (!tmp_file) {
LOG("Failed to created inode cache file: {}", tmp_file.error());
return false;
// simultaneously. Thus close the current file handle and reopen a new one,
// which will make us use the first created file even if we didn't win the
// race.
- if (link(tmp_file->path.c_str(), filename.c_str()) != 0) {
- LOG("Failed to link new inode cache: {}", strerror(errno));
+ if (auto result = fs::create_hard_link(tmp_file->path, path); !result) {
+ LOG("Failed to link new inode cache: {}", result.error());
return false;
}
#else
- if (MoveFileA(util::PathString(tmp_file->path).c_str(), filename.c_str())
+ if (MoveFileA(util::pstr(tmp_file->path).c_str(), util::pstr(path).c_str())
== 0) {
unsigned error = GetLastError();
if (error == ERROR_FILE_EXISTS) {
// Not an error, another process won the race. Remove the file we just
// created.
- DeleteFileA(util::PathString(tmp_file->path).c_str());
- LOG("Another process created inode cache {}", filename);
+ DeleteFileA(util::pstr(tmp_file->path).c_str());
+ LOG("Another process created inode cache {}", path);
return true;
} else {
LOG("Failed to move new inode cache: {}", error);
}
#endif
- LOG("Created a new inode cache {}", filename);
+ LOG("Created a new inode cache {}", path);
return true;
}
return true;
}
- std::string filename = get_file();
- if (m_sr || mmap_file(filename)) {
+ fs::path path = get_path();
+ if (m_sr || mmap_file(path)) {
return true;
}
// Try to create a new cache if we failed to map an existing file.
- create_new_file(filename);
+ create_new_file(path);
// Concurrent processes could try to create new files simultaneously and the
// file that actually landed on disk will be from the process that won the
// race. Thus we try to open the file from disk instead of reusing the file
// handle to the file we just created.
- if (mmap_file(filename)) {
+ if (mmap_file(path)) {
return true;
}
m_sr = nullptr;
m_map.unmap();
m_fd.close();
- std::string file = get_file();
- if (unlink(file.c_str()) != 0 && errno != ENOENT) {
+ fs::path path = get_path();
+ if (!fs::remove(path)) {
return false;
}
- LOG("Dropped inode cache {}", file);
+ LOG("Dropped inode cache {}", path);
return true;
}
-std::string
-InodeCache::get_file()
+fs::path
+InodeCache::get_path()
{
const uint8_t arch_bits = 8 * sizeof(void*);
- return FMT(
- "{}/inode-cache-{}.v{}", m_config.temporary_dir(), arch_bits, k_version);
+ return m_config.temporary_dir()
+ / FMT("inode-cache-{}.v{}", arch_bits, k_version);
}
int64_t
bool drop();
// Returns name of the persistent file.
- std::string get_file();
+ std::filesystem::path get_path();
// Returns total number of cache hits.
//
struct SharedRegion;
using BucketHandler = std::function<void(Bucket* bucket)>;
- bool mmap_file(const std::string& inode_cache_file);
+ bool mmap_file(const std::filesystem::path& path);
bool hash_inode(const std::filesystem::path& path,
ContentType type,
bool with_bucket(const Hash::Digest& key_digest,
const BucketHandler& bucket_handler);
- static bool create_new_file(const std::string& filename);
+ static bool create_new_file(const std::filesystem::path& path);
bool initialize();
static CleanDirResult
clean_dir(
- const std::string& l2_dir,
+ const fs::path& l2_dir,
const uint64_t max_size,
const uint64_t max_files,
const std::optional<uint64_t> max_age = std::nullopt,
uint64_t files_in_cache = 0;
auto current_time = util::TimePoint::now();
std::unordered_map<std::string /*result_file*/,
- std::vector<std::string> /*associated_raw_files*/>
+ std::vector<fs::path> /*associated_raw_files*/>
raw_files_map;
for (size_t i = 0; i < files.size();
if (namespace_ && file_type_from_path(file.path()) == FileType::raw) {
util::PathString path_str(file.path());
- const auto result_filename =
+ const std::string result_path =
FMT("{}R", path_str.str().substr(0, path_str.str().length() - 2));
- raw_files_map[result_filename].push_back(util::pstr(file.path()));
+ raw_files_map[result_path].push_back(file.path());
}
cache_size += file.size_on_disk();
FileType
file_type_from_path(const fs::path& path)
{
- std::string filename = util::pstr(path.filename());
+ std::string filename = path.filename().string();
if (util::ends_with(filename, "M")) {
return FileType::manifest;
} else if (util::ends_with(filename, "R")) {
key, -1, -static_cast<int64_t>(cache_file.dir_entry.size_on_disk() / 1024));
}
-std::string
-LocalStorage::get_raw_file_path(std::string_view result_path,
+fs::path
+LocalStorage::get_raw_file_path(const fs::path& result_path,
uint8_t file_number)
{
if (file_number >= 10) {
throw core::Error(FMT("Too high raw file entry number: {}", file_number));
}
- const auto prefix = result_path.substr(0, result_path.length() - 1);
- return FMT("{}{}W", prefix, file_number);
+ std::string s = result_path.string();
+ s.pop_back();
+ return FMT("{}{}W", s, file_number);
}
-std::string
+fs::path
LocalStorage::get_raw_file_path(const Hash::Digest& result_key,
uint8_t file_number) const
{
const std::vector<core::Result::Serializer::RawFile>& raw_files)
{
const auto cache_file = look_up_cache_file(key, core::CacheEntryType::result);
- core::ensure_dir_exists(fs::path(cache_file.path).parent_path());
+ core::ensure_dir_exists(cache_file.path.parent_path());
int64_t files_change = 0;
int64_t size_kibibyte_change = 0;
const auto zeroable_fields = core::Statistics::get_zeroable_fields();
for_each_level_1_and_2_stats_file(
- util::pstr(m_config.cache_dir()), [=](const std::string& path) {
+ m_config.cache_dir(), [=](const fs::path& path) {
StatsFile(path).update([=](auto& cs) {
for (const auto statistic : zeroable_fields) {
cs.set(statistic, 0);
// Add up the stats in each directory.
for_each_level_1_and_2_stats_file(
- util::pstr(m_config.cache_dir()), [&](const auto& path) {
+ m_config.cache_dir(), [&](const auto& path) {
counters.set(Statistic::stats_zeroed_timestamp, 0); // Don't add
counters.increment(StatsFile(path).read());
zero_timestamp = std::max(counters.get(Statistic::stats_zeroed_timestamp),
l2_progress_receiver(0.1 + 0.9 * ratio(i, files.size()));
}
- if (util::ends_with(l2_dir, "f/f")) {
+ if (l2_dir.filename() == "f"
+ && l2_dir.parent_path().filename() == "f") {
// Wait here instead of after for_each_cache_subdir to avoid
// updating the progress bar to 100% before all work is done.
thread_pool.shut_down();
// Private methods
-std::string
+fs::path
LocalStorage::get_subdir(uint8_t l1_index) const
{
- return FMT("{}/{:x}", m_config.cache_dir(), l1_index);
+ return m_config.cache_dir() / FMT("{:x}", l1_index);
}
-std::string
+fs::path
LocalStorage::get_subdir(uint8_t l1_index, uint8_t l2_index) const
{
- return FMT("{}/{:x}/{:x}", m_config.cache_dir(), l1_index, l2_index);
+ return m_config.cache_dir() / FMT("{:x}/{:x}", l1_index, l2_index);
}
LocalStorage::LookUpCacheFileResult
LocalStorage::move_to_wanted_cache_level(const StatisticsCounters& counters,
const Hash::Digest& key,
core::CacheEntryType type,
- const std::string& cache_file_path)
+ const fs::path& cache_file_path)
{
const auto wanted_level =
calculate_wanted_cache_level(counters.get(Statistic::files_in_cache));
const auto wanted_path = get_path_in_cache(
wanted_level, util::format_digest(key) + suffix_from_type(type));
if (cache_file_path != wanted_path) {
- core::ensure_dir_exists(fs::path(wanted_path).parent_path());
+ core::ensure_dir_exists(wanted_path.parent_path());
// Note: Two ccache processes may move the file at the same time, so failure
// to rename is OK.
fs::rename(cache_file_path, wanted_path);
for (const auto& raw_file : m_added_raw_files) {
fs::rename(raw_file,
- FMT("{}/{}",
- fs::path(wanted_path).parent_path(),
- fs::path(raw_file).filename()));
+ FMT("{}/{}", wanted_path.parent_path(), raw_file.filename()));
}
}
}
util::write_file(cleaned_stamp, "");
}
-std::string
+fs::path
LocalStorage::get_path_in_cache(const uint8_t level,
const std::string_view name) const
{
return (path / fs::path(name.substr(level))).string();
}
-std::string
+fs::path
LocalStorage::get_lock_path(const std::string& name) const
{
- auto path = FMT("{}/lock/{}", m_config.cache_dir(), name);
- core::ensure_dir_exists(fs::path(path).parent_path());
+ auto path = m_config.cache_dir() / "lock" / name;
+ core::ensure_dir_exists(path.parent_path());
return path;
}
void remove(const Hash::Digest& key, core::CacheEntryType type);
- static std::string get_raw_file_path(std::string_view result_path,
- uint8_t file_number);
- std::string get_raw_file_path(const Hash::Digest& result_key,
- uint8_t file_number) const;
+ static std::filesystem::path
+ get_raw_file_path(const std::filesystem::path& result_path,
+ uint8_t file_number);
+ std::filesystem::path get_raw_file_path(const Hash::Digest& result_key,
+ uint8_t file_number) const;
void put_raw_files(
const Hash::Digest& key,
// a statistics file in the finalize method.
core::StatisticsCounters m_counter_updates;
- std::vector<std::string> m_added_raw_files;
+ std::vector<std::filesystem::path> m_added_raw_files;
bool m_stored_data = false;
struct LookUpCacheFileResult
{
- std::string path;
+ std::filesystem::path path;
util::DirEntry dir_entry;
uint8_t level;
};
LookUpCacheFileResult look_up_cache_file(const Hash::Digest& key,
core::CacheEntryType type) const;
- std::string get_subdir(uint8_t l1_index) const;
- std::string get_subdir(uint8_t l1_index, uint8_t l2_index) const;
+ std::filesystem::path get_subdir(uint8_t l1_index) const;
+ std::filesystem::path get_subdir(uint8_t l1_index, uint8_t l2_index) const;
StatsFile get_stats_file(uint8_t l1_index) const;
StatsFile get_stats_file(uint8_t l1_index, uint8_t l2_index) const;
void move_to_wanted_cache_level(const core::StatisticsCounters& counters,
const Hash::Digest& key,
core::CacheEntryType type,
- const std::string& cache_file_path);
+ const std::filesystem::path& cache_file_path);
void recount_level_1_dir(util::LongLivedLockFileManager& lock_manager,
uint8_t l1_index);
struct EvaluateCleanupResult
{
uint8_t l1_index;
- std::string l1_path;
+ std::filesystem::path l1_path;
core::StatisticsCounters l1_counters;
uint64_t total_files;
};
// Join the cache directory, a '/' and `name` into a single path and return
// it. Additionally, `level` single-character, '/'-separated subpaths are
// split from the beginning of `name` before joining them all.
- std::string get_path_in_cache(uint8_t level, std::string_view name) const;
+ std::filesystem::path get_path_in_cache(uint8_t level,
+ std::string_view name) const;
- std::string get_lock_path(const std::string& name) const;
+ std::filesystem::path get_lock_path(const std::string& name) const;
util::LockFile get_auto_cleanup_lock() const;
#include <ccache/core/atomicfile.hpp>
#include <ccache/core/exceptions.hpp>
#include <ccache/util/file.hpp>
+#include <ccache/util/filesystem.hpp>
#include <ccache/util/format.hpp>
#include <ccache/util/lockfile.hpp>
#include <ccache/util/logging.hpp>
+namespace fs = util::filesystem;
+
namespace storage::local {
-StatsFile::StatsFile(const std::string& path) : m_path(path)
+StatsFile::StatsFile(const fs::path& path) : m_path(path)
{
}
#include <ccache/core/statisticscounters.hpp>
+#include <filesystem>
#include <functional>
#include <optional>
-#include <string>
namespace storage::local {
class StatsFile
{
public:
- explicit StatsFile(const std::string& path);
+ explicit StatsFile(const std::filesystem::path& path);
// Read counters. No lock is acquired. If the file doesn't exist all returned
// counters will be zero.
OnlyIfChanged only_if_changed = OnlyIfChanged::no) const;
private:
- std::string m_path;
+ std::filesystem::path m_path;
};
} // namespace storage::local
#include <ccache/core/exceptions.hpp>
#include <ccache/util/expected.hpp>
#include <ccache/util/file.hpp>
+#include <ccache/util/filesystem.hpp>
#include <ccache/util/format.hpp>
#include <ccache/util/path.hpp>
#include <ccache/util/string.hpp>
+namespace fs = util::filesystem;
+
using util::DirEntry;
namespace storage::local {
void
for_each_level_1_and_2_stats_file(
- const std::string& cache_dir,
- const std::function<void(const std::string& path)> function)
+ const fs::path& cache_dir,
+ const std::function<void(const fs::path& path)> function)
{
for (size_t level_1 = 0; level_1 <= 0xF; ++level_1) {
function(FMT("{}/{:x}/stats", cache_dir, level_1));
}
std::vector<DirEntry>
-get_cache_dir_files(const std::string& dir)
+get_cache_dir_files(const fs::path& dir)
{
std::vector<DirEntry> files;
#include <ccache/util/direntry.hpp>
+#include <filesystem>
#include <functional>
-#include <string>
#include <vector>
namespace storage::local {
const SubdirProgressVisitor& visitor);
void for_each_level_1_and_2_stats_file(
- const std::string& cache_dir,
- const std::function<void(const std::string& path)> function);
+ const std::filesystem::path& cache_dir,
+ const std::function<void(const std::filesystem::path& path)> function);
// Get a list of files in a subdirectory of the cache.
//
// - CACHEDIR.TAG
// - stats
// - .nfs* (temporary NFS files that may be left for open but deleted files).
-std::vector<util::DirEntry> get_cache_dir_files(const std::string& dir);
+std::vector<util::DirEntry>
+get_cache_dir_files(const std::filesystem::path& dir);
} // namespace storage::local
}
void
-dump_log(const std::string& path)
+dump_log(const fs::path& path)
{
if (!enabled()) {
return;
void bulk_log(std::string_view message);
// Write the current log memory buffer to `path`.
-void dump_log(const std::string& path);
+void dump_log(const std::filesystem::path& path);
} // namespace util::logging
InodeCache inode_cache(config, util::Duration(0));
inode_cache.get("a", InodeCache::ContentType::raw);
- CHECK(util::DirEntry(inode_cache.get_file()));
+ CHECK(util::DirEntry(inode_cache.get_path()));
CHECK(inode_cache.drop());
- CHECK(!util::DirEntry(inode_cache.get_file()));
+ CHECK(!util::DirEntry(inode_cache.get_path()));
CHECK(inode_cache.drop());
}