1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-22 17:01:08 +01:00

libutil: Fix canonPath, makeTempPath and createTempDir on windows

This at least makes canonPath not consider the drive letter as a path
component. There still some issues with it on windows, but at least
this gets us through some of the libutil-tests.

Also since we don't want to change which env variables nix considers
we don't use std::filesystem::temp_directory_path and implement the
windows version directly.
This commit is contained in:
Sergei Zimmerman 2025-12-17 23:45:18 +03:00
parent 2f092870e4
commit 675656ffba
No known key found for this signature in database
6 changed files with 49 additions and 12 deletions

View file

@ -416,4 +416,11 @@ TEST(FdSource, restartWorks)
EXPECT_EQ(source.drain(), ""); EXPECT_EQ(source.drain(), "");
} }
TEST(createTempDir, works)
{
auto tmpDir = createTempDir();
nix::AutoDelete delTmpDir(tmpDir, /*recursive=*/true);
ASSERT_TRUE(std::filesystem::is_directory(tmpDir));
}
} // namespace nix } // namespace nix

View file

@ -115,9 +115,6 @@ Path canonPath(PathView path, bool resolveSymlinks)
if (!isAbsolute(path)) if (!isAbsolute(path))
throw Error("not an absolute path: '%1%'", path); throw Error("not an absolute path: '%1%'", path);
// For Windows
auto rootName = std::filesystem::path{path}.root_name();
/* This just exists because we cannot set the target of `remaining` /* This just exists because we cannot set the target of `remaining`
(the callback parameter) directly to a newly-constructed string, (the callback parameter) directly to a newly-constructed string,
since it is `std::string_view`. */ since it is `std::string_view`. */
@ -147,8 +144,6 @@ Path canonPath(PathView path, bool resolveSymlinks)
} }
}); });
if (!rootName.empty())
ret = rootName.string() + std::move(ret);
return ret; return ret;
} }
@ -672,11 +667,6 @@ void AutoUnmount::cancel()
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
std::filesystem::path defaultTempDir()
{
return getEnvNonEmpty("TMPDIR").value_or("/tmp");
}
std::filesystem::path createTempDir(const std::filesystem::path & tmpRoot, const std::string & prefix, mode_t mode) std::filesystem::path createTempDir(const std::filesystem::path & tmpRoot, const std::string & prefix, mode_t mode)
{ {
while (1) { while (1) {

View file

@ -40,6 +40,11 @@ struct UnixPathTrait
{ {
return path.rfind('/', from); return path.rfind('/', from);
} }
static size_t rootNameLen(StringView)
{
return 0;
}
}; };
/** /**
@ -83,6 +88,18 @@ struct WindowsPathTrait
size_t p2 = path.rfind(preferredSep, from); size_t p2 = path.rfind(preferredSep, from);
return p1 == String::npos ? p2 : p2 == String::npos ? p1 : std::max(p1, p2); return p1 == String::npos ? p2 : p2 == String::npos ? p1 : std::max(p1, p2);
} }
static size_t rootNameLen(StringView path)
{
if (path.size() >= 2 && path[1] == ':') {
char driveLetter = path[0];
if ((driveLetter >= 'A' && driveLetter <= 'Z') || (driveLetter >= 'a' && driveLetter <= 'z'))
return 2;
}
/* TODO: This needs to also handle UNC paths.
* https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#unc-paths */
return 0;
}
}; };
template<typename CharT> template<typename CharT>
@ -116,6 +133,11 @@ typename PathDict::String canonPathInner(typename PathDict::StringView remaining
typename PathDict::String result; typename PathDict::String result;
result.reserve(256); result.reserve(256);
if (auto rootNameLength = PathDict::rootNameLen(remaining)) {
result += remaining.substr(0, rootNameLength); /* Copy drive letter verbatim. */
remaining.remove_prefix(rootNameLength);
}
while (true) { while (true) {
/* Skip slashes. */ /* Skip slashes. */

View file

@ -362,6 +362,8 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix = "nix");
/** /**
* Return `TMPDIR`, or the default temporary directory if unset or empty. * Return `TMPDIR`, or the default temporary directory if unset or empty.
* Uses GetTempPathW on windows which respects TMP, TEMP, USERPROFILE env variables.
* Does not resolve symlinks and the returned path might not be directory or exist at all.
*/ */
std::filesystem::path defaultTempDir(); std::filesystem::path defaultTempDir();

View file

@ -9,6 +9,7 @@
#include <unistd.h> #include <unistd.h>
#include "nix/util/file-system.hh" #include "nix/util/file-system.hh"
#include "nix/util/environment-variables.hh"
#include "util-unix-config-private.hh" #include "util-unix-config-private.hh"
@ -19,6 +20,11 @@ Descriptor openDirectory(const std::filesystem::path & path)
return open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC); return open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
} }
std::filesystem::path defaultTempDir()
{
return getEnvNonEmpty("TMPDIR").value_or("/tmp");
}
void setWriteTime( void setWriteTime(
const std::filesystem::path & path, time_t accessedTime, time_t modificationTime, std::optional<bool> optIsSymlink) const std::filesystem::path & path, time_t accessedTime, time_t modificationTime, std::optional<bool> optIsSymlink)
{ {

View file

@ -1,9 +1,11 @@
#include "nix/util/file-system.hh" #include "nix/util/file-system.hh"
#include "nix/util/windows-error.hh"
#include "nix/util/logging.hh" #include "nix/util/logging.hh"
#ifdef _WIN32
namespace nix { namespace nix {
using namespace nix::windows;
void setWriteTime( void setWriteTime(
const std::filesystem::path & path, time_t accessedTime, time_t modificationTime, std::optional<bool> optIsSymlink) const std::filesystem::path & path, time_t accessedTime, time_t modificationTime, std::optional<bool> optIsSymlink)
{ {
@ -28,5 +30,13 @@ Descriptor openDirectory(const std::filesystem::path & path)
NULL); NULL);
} }
std::filesystem::path defaultTempDir()
{
wchar_t buf[MAX_PATH + 1];
DWORD len = GetTempPathW(MAX_PATH + 1, buf);
if (len == 0 || len > MAX_PATH)
throw WinError("getting default temporary directory");
return std::filesystem::path(buf);
}
} // namespace nix } // namespace nix
#endif