]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
perf: Use util::PathString instead of fs::path copy
authorJoel Rosdahl <joel@rosdahl.net>
Sat, 20 Jan 2024 14:03:02 +0000 (15:03 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Sat, 27 Jan 2024 09:50:16 +0000 (10:50 +0100)
src/argprocessing.cpp
src/ccache.cpp
src/core/common.cpp
src/core/mainoptions.cpp
src/execute.cpp
src/storage/local/LocalStorage.cpp
src/storage/local/util.cpp
src/util/DirEntry.cpp
src/util/LockFile.cpp
src/util/TemporaryFile.cpp
src/util/file.cpp

index 9f6001dd8f936b6aaf39c8b56a0ef69a43e70a92..a61317e5f7387d8d931c3d3930d0aaa533d938d1 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <Depfile.hpp>
 #include <Util.hpp>
+#include <util/PathString.hpp>
 #include <util/assertions.hpp>
 #include <util/filesystem.hpp>
 #include <util/fmtmacros.hpp>
 #include <vector>
 
 namespace fs = util::filesystem;
+
 using core::Statistic;
 using util::DirEntry;
+using pstr = util::PathString;
 
 namespace {
 
@@ -162,7 +165,7 @@ detect_pch(const std::string& option,
       fs::path file = fs::path(arg).replace_extension(".pch");
       if (fs::is_regular_file(file)) {
         LOG("Detected use of precompiled header: {}", file);
-        pch_file = file.string();
+        pch_file = pstr(file).str();
       }
     }
   } else if (option == "-Fp") {
@@ -1232,7 +1235,7 @@ process_args(Context& ctx)
   if (state.input_files.size() > 1) {
     if (is_link) {
       LOG_RAW("Called for link");
-      return state.input_files.front().string().find("conftest.")
+      return pstr(state.input_files.front()).str().find("conftest.")
                  != std::string::npos
                ? Statistic::autoconf_test
                : Statistic::called_for_link;
@@ -1242,7 +1245,7 @@ process_args(Context& ctx)
     }
   }
 
-  args_info.orig_input_file = state.input_files.front().string();
+  args_info.orig_input_file = pstr(state.input_files.front()).str();
   // Rewrite to relative to increase hit rate.
   args_info.input_file =
     Util::make_relative_path(ctx, args_info.orig_input_file);
@@ -1293,10 +1296,10 @@ process_args(Context& ctx)
     } else {
       extension = get_default_object_file_extension(ctx.config);
     }
-    args_info.output_obj += fs::path(args_info.input_file)
-                              .filename()
-                              .replace_extension(extension)
-                              .string();
+    args_info.output_obj +=
+      pstr(
+        fs::path(args_info.input_file).filename().replace_extension(extension))
+        .str();
   }
 
   args_info.orig_output_obj = args_info.output_obj;
@@ -1425,7 +1428,7 @@ process_args(Context& ctx)
       args_info.seen_split_dwarf = false;
     } else {
       args_info.output_dwo =
-        fs::path(args_info.output_obj).replace_extension(".dwo").string();
+        pstr(fs::path(args_info.output_obj).replace_extension(".dwo")).str();
     }
   }
 
@@ -1487,7 +1490,7 @@ process_args(Context& ctx)
   if (args_info.generating_dependencies) {
     if (state.output_dep_origin == OutputDepOrigin::none) {
       args_info.output_dep =
-        fs::path(args_info.output_obj).replace_extension(".d").string();
+        pstr(fs::path(args_info.output_obj).replace_extension(".d")).str();
       if (!config.run_second_cpp()) {
         // If we're compiling preprocessed code we're sending dep_args to the
         // preprocessor so we need to use -MF to write to the correct .d file
index 66420e24189625d820520ef63b9031cb3e7aa7b9..d73f4dec6a1436cdeb76516630631bdc0add0dce 100644 (file)
@@ -48,6 +48,7 @@
 #include <util/Fd.hpp>
 #include <util/FileStream.hpp>
 #include <util/Finalizer.hpp>
+#include <util/PathString.hpp>
 #include <util/TemporaryFile.hpp>
 #include <util/UmaskScope.hpp>
 #include <util/environment.hpp>
@@ -82,6 +83,7 @@ namespace fs = util::filesystem;
 
 using core::Statistic;
 using util::DirEntry;
+using pstr = util::PathString;
 
 // This is a string that identifies the current "version" of the hash sum
 // computed by ccache. If, for any reason, we want to force the hash sum to be
@@ -207,7 +209,7 @@ prepare_debug_path(const fs::path& cwd,
              static_cast<long long unsigned int>(time_of_invocation.sec()));
   }
   return FMT("{}.{}_{:06}.ccache-{}",
-             prefix.string(),
+             pstr(prefix).str(),
              timestamp,
              time_of_invocation.nsec_decimal_part() / 1000,
              suffix);
@@ -265,7 +267,7 @@ static CompilerType
 do_guess_compiler(const fs::path& path)
 {
   const auto name =
-    util::to_lowercase(path.filename().replace_extension("").string());
+    util::to_lowercase(pstr(path.filename().replace_extension("")).str());
   if (name.find("clang-cl") != std::string_view::npos) {
     return CompilerType::clang_cl;
   } else if (name.find("clang") != std::string_view::npos) {
@@ -673,7 +675,7 @@ get_tmp_fd(Context& ctx,
     auto tmp_stdout =
       util::value_or_throw<core::Fatal>(util::TemporaryFile::create(
         FMT("{}/{}", ctx.config.temporary_dir(), description)));
-    ctx.register_pending_tmp_file(tmp_stdout.path.string());
+    ctx.register_pending_tmp_file(pstr(tmp_stdout.path));
     return {std::move(tmp_stdout.fd), std::move(tmp_stdout.path)};
   } else {
     const auto dev_null_path = util::get_dev_null_path();
@@ -1439,7 +1441,7 @@ hash_common_info(const Context& ctx,
   // Also hash the compiler name as some compilers use hard links and behave
   // differently depending on the real name.
   hash.hash_delimiter("cc_name");
-  hash.hash(fs::path(args[0]).filename().string());
+  hash.hash(pstr(fs::path(args[0]).filename()).str());
 
   // Hash variables that may affect the compilation.
   const char* always_hash_env_vars[] = {
@@ -1570,7 +1572,7 @@ hash_common_info(const Context& ctx,
          util::split_path_list(ctx.config.extra_files_to_hash())) {
       LOG("Hashing extra file {}", path);
       hash.hash_delimiter("extrafile");
-      if (!hash_binary_file(ctx, hash, path.string())) {
+      if (!hash_binary_file(ctx, hash, pstr(path))) {
         return tl::unexpected(Statistic::error_hashing_extra_file);
       }
     }
@@ -1889,7 +1891,7 @@ hash_profile_data_file(const Context& ctx, Hash& hash)
 {
   const std::string& profile_path = ctx.args_info.profile_path;
   const std::string base_name =
-    fs::path(ctx.args_info.output_obj).replace_extension("").string();
+    pstr(fs::path(ctx.args_info.output_obj).replace_extension("")).str();
   std::string hashified_cwd = ctx.apparent_cwd;
   std::replace(hashified_cwd.begin(), hashified_cwd.end(), '/', '#');
 
@@ -2742,8 +2744,9 @@ ccache_main(int argc, const char* const* argv)
   try {
     if (is_ccache_executable(argv[0])) {
       if (argc < 2) {
-        PRINT_RAW(stderr,
-                  core::get_usage_text(fs::path(argv[0]).filename().string()));
+        PRINT_RAW(
+          stderr,
+          core::get_usage_text(pstr(fs::path(argv[0]).filename()).str()));
         exit(EXIT_FAILURE);
       }
       // If the first argument isn't an option, then assume we are being
index 1a69f815bb8f27336eb71e074fd054d73dac7742..29b825a61777add6d09c274a6694926a4ed6e59b 100644 (file)
@@ -21,6 +21,7 @@
 #include <Context.hpp>
 #include <core/exceptions.hpp>
 #include <util/Finalizer.hpp>
+#include <util/PathString.hpp>
 #include <util/Tokenizer.hpp>
 #include <util/expected.hpp>
 #include <util/file.hpp>
@@ -29,6 +30,7 @@
 #include <util/path.hpp>
 
 using IncludeDelimiter = util::Tokenizer::IncludeDelimiter;
+using pstr = util::PathString;
 
 namespace fs = util::filesystem;
 
@@ -104,7 +106,7 @@ rewrite_stderr_to_absolute_paths(std::string_view text)
       result.append(line.data(), line.length());
     } else {
       fs::path path(line.substr(0, path_end));
-      result += fs::canonical(path).value_or(path).string();
+      result += pstr(fs::canonical(path).value_or(path)).str();
       auto tail = line.substr(path_end);
       result.append(tail.data(), tail.length());
     }
index 371a272fa63ec4af1928ff1f4f0c3ce92d711182..37d45fee3bb221083b8e696fc707df5f75e2c089 100644 (file)
@@ -37,6 +37,7 @@
 #include <storage/local/LocalStorage.hpp>
 #include <util/Fd.hpp>
 #include <util/FileStream.hpp>
+#include <util/PathString.hpp>
 #include <util/TemporaryFile.hpp>
 #include <util/TextTable.hpp>
 #include <util/ThreadPool.hpp>
@@ -77,6 +78,7 @@ extern "C" {
 namespace fs = util::filesystem;
 
 using util::DirEntry;
+using pstr = util::PathString;
 
 namespace core {
 
@@ -791,7 +793,7 @@ process_main_options(int argc, const char* const* argv)
 
     case 'V': // --version
     {
-      PRINT_RAW(stdout, get_version_text(fs::path(argv[0]).stem().string()));
+      PRINT_RAW(stdout, get_version_text(pstr(fs::path(argv[0]).stem()).str()));
       break;
     }
 
index efa89558c3d0695f1b4bf6e2e7100d53b50c7c37..0c51671bf589c6c814c3fbaa1e4b72327b6149b4 100644 (file)
@@ -29,6 +29,7 @@
 #include <util/DirEntry.hpp>
 #include <util/Fd.hpp>
 #include <util/Finalizer.hpp>
+#include <util/PathString.hpp>
 #include <util/TemporaryFile.hpp>
 #include <util/error.hpp>
 #include <util/expected.hpp>
@@ -52,6 +53,8 @@
 
 namespace fs = util::filesystem;
 
+using pstr = util::PathString;
+
 #ifdef _WIN32
 static int win32execute(const char* path,
                         const char* const* argv,
@@ -87,9 +90,9 @@ win32getshell(const std::string& path)
 {
   const char* path_list = getenv("PATH");
   std::string sh;
-  if (util::to_lowercase(fs::path(path).extension().string()) == ".sh"
+  if (util::to_lowercase(pstr(fs::path(path).extension()).str()) == ".sh"
       && path_list) {
-    sh = find_executable_in_path("sh.exe", path_list).string();
+    sh = pstr(find_executable_in_path("sh.exe", path_list)).str();
   }
   if (sh.empty() && getenv("CCACHE_DETECT_SHEBANG")) {
     // Detect shebang.
@@ -98,7 +101,7 @@ win32getshell(const std::string& path)
       char buf[10] = {0};
       fgets(buf, sizeof(buf) - 1, fp.get());
       if (std::string(buf) == "#!/bin/sh" && path_list) {
-        sh = find_executable_in_path("sh.exe", path_list).string();
+        sh = pstr(find_executable_in_path("sh.exe", path_list)).str();
       }
     }
   }
index daac0fbe7469978b761ab1386f9f271e999a339a..65d1615f681dc5a81b50361656b6d53d40846a9a 100644 (file)
@@ -30,6 +30,7 @@
 #include <core/exceptions.hpp>
 #include <util/Duration.hpp>
 #include <util/FileStream.hpp>
+#include <util/PathString.hpp>
 #include <util/TemporaryFile.hpp>
 #include <util/TextTable.hpp>
 #include <util/ThreadPool.hpp>
@@ -89,6 +90,8 @@ using core::Statistic;
 using core::StatisticsCounters;
 using util::DirEntry;
 
+using pstr = util::PathString;
+
 namespace storage::local {
 
 // How often (in seconds) to scan $CCACHE_DIR/tmp for left-over temporary
@@ -343,15 +346,15 @@ clean_dir(
     // Delete any tmp files older than 1 hour right away.
     if (file.mtime() + util::Duration(3600) < current_time
         && util::TemporaryFile::is_tmp_file(file.path())) {
-      util::remove(file.path().string());
+      util::remove(file.path());
       continue;
     }
 
     if (namespace_ && file_type_from_path(file.path()) == FileType::raw) {
+      auto path_str = pstr(file.path());
       const auto result_filename =
-        FMT("{}R",
-            file.path().string().substr(0, file.path().string().length() - 2));
-      raw_files_map[result_filename].push_back(file.path().string());
+        FMT("{}R", path_str.str().substr(0, path_str.str().length() - 2));
+      raw_files_map[result_filename].push_back(pstr(file.path()).str());
     }
 
     cache_size += file.size_on_disk();
@@ -399,7 +402,7 @@ clean_dir(
       // For namespace eviction we need to remove raw files based on result
       // filename since they don't have a header.
       if (file_type_from_path(file.path()) == FileType::result) {
-        const auto entry = raw_files_map.find(file.path().string());
+        const auto entry = raw_files_map.find(pstr(file.path()));
         if (entry != raw_files_map.end()) {
           for (const auto& raw_file : entry->second) {
             delete_file(DirEntry(raw_file), cache_size, files_in_cache);
@@ -427,7 +430,7 @@ clean_dir(
 FileType
 file_type_from_path(const fs::path& path)
 {
-  auto filename = path.filename().string();
+  std::string filename = pstr(path.filename()).str();
   if (util::ends_with(filename, "M")) {
     return FileType::manifest;
   } else if (util::ends_with(filename, "R")) {
index 9d8e9d6645e6a643eb24ace0c55c90adb1a7ddde..50ba754d237ed229733db67ea8eb8293a489caf2 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2021-2023 Joel Rosdahl and other contributors
+// Copyright (C) 2021-2024 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
 
 #include <Util.hpp>
 #include <core/exceptions.hpp>
+#include <util/PathString.hpp>
 #include <util/expected.hpp>
 #include <util/file.hpp>
 #include <util/fmtmacros.hpp>
 #include <util/string.hpp>
 
 using util::DirEntry;
+using pstr = util::PathString;
 
 namespace storage::local {
 
@@ -74,7 +76,7 @@ get_cache_dir_files(const std::string& dir)
   }
   util::throw_on_error<core::Error>(
     util::traverse_directory(dir, [&](const auto& de) {
-      auto name = de.path().filename().string();
+      std::string name = pstr(de.path().filename()).str();
       if (name == "CACHEDIR.TAG" || name == "stats"
           || util::starts_with(name, ".nfs")) {
         return;
index b031181c5e903fb5c234c8825049720662748db3..1f4388f6f593932d2976d293fe693ec6aafdd4fe 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2019-2023 Joel Rosdahl and other contributors
+// Copyright (C) 2019-2024 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
@@ -19,6 +19,7 @@
 #include "DirEntry.hpp"
 
 #include <util/Finalizer.hpp>
+#include <util/PathString.hpp>
 #include <util/file.hpp>
 #include <util/fmtmacros.hpp>
 #include <util/logging.hpp>
@@ -28,6 +29,8 @@
 #  include <third_party/win32/winerror_to_errno.h>
 #endif
 
+using pstr = util::PathString;
+
 namespace {
 
 #ifdef _WIN32
@@ -249,7 +252,9 @@ DirEntry::do_stat() const
     m_exists = false;
     m_is_symlink = false;
 
-    int result = lstat_func(m_path.string().c_str(), &m_stat);
+    auto path = pstr(m_path);
+
+    int result = lstat_func(path, &m_stat);
     if (result == 0) {
       m_errno = 0;
       if (S_ISLNK(m_stat.st_mode)
@@ -259,7 +264,7 @@ DirEntry::do_stat() const
       ) {
         m_is_symlink = true;
         stat_t st;
-        if (stat_func(m_path.string().c_str(), &st) == 0) {
+        if (stat_func(path, &st) == 0) {
           m_stat = st;
           m_exists = true;
         }
@@ -269,7 +274,7 @@ DirEntry::do_stat() const
     } else {
       m_errno = errno;
       if (m_log_on_error == LogOnError::yes) {
-        LOG("Failed to lstat {}: {}", m_path.string(), strerror(m_errno));
+        LOG("Failed to lstat {}: {}", m_path, strerror(m_errno));
       }
     }
 
index 3a60cfacbdaa971a72b5a3c92efc6b570e675a17..55ffc0fc28d3c27b8bb7fe655d98c05fa964741f 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2020-2023 Joel Rosdahl and other contributors
+// Copyright (C) 2020-2024 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
@@ -21,6 +21,7 @@
 #include "Util.hpp"
 
 #include <util/DirEntry.hpp>
+#include <util/PathString.hpp>
 #include <util/assertions.hpp>
 #include <util/error.hpp>
 #include <util/file.hpp>
@@ -46,6 +47,8 @@ const util::Duration k_staleness_limit(2);
 
 namespace fs = util::filesystem;
 
+using pstr = util::PathString;
+
 namespace {
 
 class RandomNumberGenerator
@@ -74,9 +77,9 @@ private:
 namespace util {
 
 LockFile::LockFile(const fs::path& path)
-  : m_lock_file(path.string() + ".lock"),
+  : m_lock_file(pstr(path).str() + ".lock"),
 #ifndef _WIN32
-    m_alive_file(path.string() + ".alive"),
+    m_alive_file(pstr(path).str() + ".alive"),
     m_acquired(false)
 #else
     m_handle(INVALID_HANDLE_VALUE)
@@ -360,7 +363,7 @@ LockFile::do_acquire(const bool blocking)
 
   while (true) {
     DWORD flags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE;
-    handle = CreateFile(m_lock_file.string().c_str(),
+    handle = CreateFile(pstr(m_lock_file),
                         GENERIC_WRITE, // desired access
                         0,             // shared mode (0 = not shared)
                         nullptr,       // security attributes
index 744b46a3c33fa89dbac672d4016471f269c28aba..1964174cbfb01900434c1ec0e7fa4b570cc96aab 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "TemporaryFile.hpp"
 
+#include <util/PathString.hpp>
 #include <util/file.hpp>
 #include <util/filesystem.hpp>
 #include <util/fmtmacros.hpp>
@@ -35,6 +36,8 @@
 
 namespace fs = util::filesystem;
 
+using pstr = util::PathString;
+
 namespace util {
 
 TemporaryFile::TemporaryFile(Fd&& fd_, const fs::path& path_)
@@ -81,7 +84,7 @@ TemporaryFile::create(const fs::path& path_prefix, std::string_view suffix)
 bool
 TemporaryFile::is_tmp_file(const fs::path& path)
 {
-  return path.filename().string().find(tmp_file_infix) != std::string::npos;
+  return pstr(path.filename()).str().find(tmp_file_infix) != std::string::npos;
 }
 
 } // namespace util
index 11d5bacccbb11db377defac56290286d1add3e81..51a99984431e69c120a0de6a30d22a0f9459b13f 100644 (file)
@@ -22,6 +22,7 @@
 #include <util/DirEntry.hpp>
 #include <util/Fd.hpp>
 #include <util/Finalizer.hpp>
+#include <util/PathString.hpp>
 #include <util/TemporaryFile.hpp>
 #include <util/error.hpp>
 #include <util/expected.hpp>
 
 namespace fs = util::filesystem;
 
+using pstr = util::PathString;
+
 namespace util {
 
 tl::expected<void, std::string>
 copy_file(const fs::path& src, const fs::path& dest, ViaTmpFile via_tmp_file)
 {
-  Fd src_fd(open(src.string().c_str(), O_RDONLY | O_BINARY));
+  Fd src_fd(open(pstr(src), O_RDONLY | O_BINARY));
   if (!src_fd) {
     return tl::unexpected(
       FMT("Failed to open {} for reading: {}", src, strerror(errno)));
   }
 
-  unlink(dest.string().c_str());
+  unlink(pstr(dest));
 
   Fd dest_fd;
   fs::path tmp_file;
@@ -85,8 +88,8 @@ copy_file(const fs::path& src, const fs::path& dest, ViaTmpFile via_tmp_file)
     dest_fd = std::move(temp_file->fd);
     tmp_file = std::move(temp_file->path);
   } else {
-    dest_fd = Fd(open(
-      dest.string().c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666));
+    dest_fd =
+      Fd(open(pstr(dest), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666));
     if (!dest_fd) {
       return tl::unexpected(
         FMT("Failed to open {} for writing: {}", dest, strerror(errno)));
@@ -247,7 +250,7 @@ read_file(const fs::path& path, size_t size_hint)
       return O_RDONLY | O_BINARY;
     }
   }();
-  Fd fd(open(path.string().c_str(), open_flags));
+  Fd fd(open(pstr(path), open_flags));
   if (!fd) {
     return tl::unexpected(strerror(errno));
   }
@@ -340,7 +343,7 @@ read_file_part(const fs::path& path, size_t pos, size_t count)
     return result;
   }
 
-  Fd fd(open(path.string().c_str(), O_RDONLY | O_BINARY));
+  Fd fd(open(pstr(path), O_RDONLY | O_BINARY));
   if (!fd) {
     LOG("Failed to open {}: {}", path, strerror(errno));
     return tl::unexpected(strerror(errno));
@@ -445,7 +448,7 @@ set_timestamps(const fs::path& path,
     atime_mtime[0] = (atime ? *atime : *mtime).to_timespec();
     atime_mtime[1] = mtime->to_timespec();
   }
-  utimensat(AT_FDCWD, path.string().c_str(), mtime ? atime_mtime : nullptr, 0);
+  utimensat(AT_FDCWD, pstr(path), mtime ? atime_mtime : nullptr, 0);
 #elif defined(HAVE_UTIMES)
   timeval atime_mtime[2];
   if (mtime) {
@@ -455,15 +458,15 @@ set_timestamps(const fs::path& path,
     atime_mtime[1].tv_sec = mtime->sec();
     atime_mtime[1].tv_usec = mtime->nsec_decimal_part() / 1000;
   }
-  utimes(path.string().c_str(), mtime ? atime_mtime : nullptr);
+  utimes(pstr(path), mtime ? atime_mtime : nullptr);
 #else
   utimbuf atime_mtime;
   if (mtime) {
     atime_mtime.actime = atime ? atime->sec() : mtime->sec();
     atime_mtime.modtime = mtime->sec();
-    utime(path.string().c_str(), &atime_mtime);
+    utime(pstr(path), &atime_mtime);
   } else {
-    utime(path.string().c_str(), nullptr);
+    utime(pstr(path), nullptr);
   }
 #endif
 }
@@ -474,7 +477,7 @@ tl::expected<void, std::string>
 traverse_directory(const fs::path& directory,
                    const TraverseDirectoryVisitor& visitor)
 {
-  DIR* dir = opendir(directory.string().c_str());
+  DIR* dir = opendir(pstr(directory));
   if (!dir) {
     return tl::unexpected(
       FMT("Failed to traverse {}: {}", directory, strerror(errno)));
@@ -575,11 +578,11 @@ write_fd(int fd, const void* data, size_t size)
 tl::expected<void, std::string>
 write_file(const fs::path& path, std::string_view data, InPlace in_place)
 {
+  auto path_str = pstr(path);
   if (in_place == InPlace::no) {
-    unlink(path.string().c_str());
+    unlink(path_str);
   }
-  Fd fd(
-    open(path.string().c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, 0666));
+  Fd fd(open(path_str, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, 0666));
   if (!fd) {
     return tl::unexpected(strerror(errno));
   }
@@ -591,11 +594,11 @@ write_file(const fs::path& path,
            nonstd::span<const uint8_t> data,
            InPlace in_place)
 {
+  auto path_str = pstr(path);
   if (in_place == InPlace::no) {
-    unlink(path.string().c_str());
+    unlink(path_str);
   }
-  Fd fd(
-    open(path.string().c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666));
+  Fd fd(open(path_str, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666));
   if (!fd) {
     return tl::unexpected(strerror(errno));
   }