mirror of
https://github.com/NixOS/nix.git
synced 2025-12-22 08:51:08 +01:00
Merge pull request #14819 from NixOS/mingw-fixes-more
Assorted windows fixes for libutil, HANDLEs and path handling
This commit is contained in:
commit
1aa7ab0dcf
10 changed files with 276 additions and 185 deletions
|
|
@ -388,14 +388,13 @@ TEST(openFileEnsureBeneathNoSymlinks, works)
|
|||
TEST(createAnonymousTempFile, works)
|
||||
{
|
||||
auto fd = createAnonymousTempFile();
|
||||
auto fd_ = fromDescriptorReadOnly(fd.get());
|
||||
writeFull(fd.get(), "test");
|
||||
lseek(fd_, 0, SEEK_SET);
|
||||
lseek(fd.get(), 0, SEEK_SET);
|
||||
FdSource source{fd.get()};
|
||||
EXPECT_EQ(source.drain(), "test");
|
||||
lseek(fd_, 0, SEEK_END);
|
||||
lseek(fd.get(), 0, SEEK_END);
|
||||
writeFull(fd.get(), "test");
|
||||
lseek(fd_, 0, SEEK_SET);
|
||||
lseek(fd.get(), 0, SEEK_SET);
|
||||
EXPECT_EQ(source.drain(), "testtest");
|
||||
}
|
||||
|
||||
|
|
@ -406,9 +405,8 @@ TEST(createAnonymousTempFile, works)
|
|||
TEST(FdSource, restartWorks)
|
||||
{
|
||||
auto fd = createAnonymousTempFile();
|
||||
auto fd_ = fromDescriptorReadOnly(fd.get());
|
||||
writeFull(fd.get(), "hello world");
|
||||
lseek(fd_, 0, SEEK_SET);
|
||||
lseek(fd.get(), 0, SEEK_SET);
|
||||
FdSource source{fd.get()};
|
||||
EXPECT_EQ(source.drain(), "hello world");
|
||||
source.restart();
|
||||
|
|
@ -416,4 +414,11 @@ TEST(FdSource, restartWorks)
|
|||
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
|
||||
|
|
|
|||
|
|
@ -115,9 +115,6 @@ Path canonPath(PathView path, bool resolveSymlinks)
|
|||
if (!isAbsolute(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`
|
||||
(the callback parameter) directly to a newly-constructed string,
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -380,14 +375,6 @@ void syncParent(const Path & path)
|
|||
fd.fsync();
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
# define MOUNTEDPATHS_PARAM , std::set<Path> & mountedPaths
|
||||
# define MOUNTEDPATHS_ARG , mountedPaths
|
||||
#else
|
||||
# define MOUNTEDPATHS_PARAM
|
||||
# define MOUNTEDPATHS_ARG
|
||||
#endif
|
||||
|
||||
void recursiveSync(const Path & path)
|
||||
{
|
||||
/* If it's a file or symlink, just fsync and return. */
|
||||
|
|
@ -432,129 +419,6 @@ void recursiveSync(const Path & path)
|
|||
}
|
||||
}
|
||||
|
||||
static void _deletePath(
|
||||
Descriptor parentfd,
|
||||
const std::filesystem::path & path,
|
||||
uint64_t & bytesFreed,
|
||||
std::exception_ptr & ex MOUNTEDPATHS_PARAM)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
checkInterrupt();
|
||||
|
||||
# ifdef __FreeBSD__
|
||||
// In case of emergency (unmount fails for some reason) not recurse into mountpoints.
|
||||
// This prevents us from tearing up the nullfs-mounted nix store.
|
||||
if (mountedPaths.find(path) != mountedPaths.end()) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
std::string name(path.filename());
|
||||
assert(name != "." && name != ".." && !name.empty());
|
||||
|
||||
struct stat st;
|
||||
if (fstatat(parentfd, name.c_str(), &st, AT_SYMLINK_NOFOLLOW) == -1) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
throw SysError("getting status of %1%", path);
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
/* We are about to delete a file. Will it likely free space? */
|
||||
|
||||
switch (st.st_nlink) {
|
||||
/* Yes: last link. */
|
||||
case 1:
|
||||
bytesFreed += st.st_size;
|
||||
break;
|
||||
/* Maybe: yes, if 'auto-optimise-store' or manual optimisation
|
||||
was performed. Instead of checking for real let's assume
|
||||
it's an optimised file and space will be freed.
|
||||
|
||||
In worst case we will double count on freed space for files
|
||||
with exactly two hardlinks for unoptimised packages.
|
||||
*/
|
||||
case 2:
|
||||
bytesFreed += st.st_size;
|
||||
break;
|
||||
/* No: 3+ links. */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* Make the directory accessible. */
|
||||
const auto PERM_MASK = S_IRUSR | S_IWUSR | S_IXUSR;
|
||||
if ((st.st_mode & PERM_MASK) != PERM_MASK) {
|
||||
if (fchmodat(parentfd, name.c_str(), st.st_mode | PERM_MASK, 0) == -1)
|
||||
throw SysError("chmod %1%", path);
|
||||
}
|
||||
|
||||
int fd = openat(parentfd, name.c_str(), O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
|
||||
if (fd == -1)
|
||||
throw SysError("opening directory %1%", path);
|
||||
AutoCloseDir dir(fdopendir(fd));
|
||||
if (!dir)
|
||||
throw SysError("opening directory %1%", path);
|
||||
|
||||
struct dirent * dirent;
|
||||
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
|
||||
checkInterrupt();
|
||||
std::string childName = dirent->d_name;
|
||||
if (childName == "." || childName == "..")
|
||||
continue;
|
||||
_deletePath(dirfd(dir.get()), path / childName, bytesFreed, ex MOUNTEDPATHS_ARG);
|
||||
}
|
||||
if (errno)
|
||||
throw SysError("reading directory %1%", path);
|
||||
}
|
||||
|
||||
int flags = S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0;
|
||||
if (unlinkat(parentfd, name.c_str(), flags) == -1) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
try {
|
||||
throw SysError("cannot unlink %1%", path);
|
||||
} catch (...) {
|
||||
if (!ex)
|
||||
ex = std::current_exception();
|
||||
else
|
||||
ignoreExceptionExceptInterrupt();
|
||||
}
|
||||
}
|
||||
#else
|
||||
// TODO implement
|
||||
throw UnimplementedError("_deletePath");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _deletePath(const std::filesystem::path & path, uint64_t & bytesFreed MOUNTEDPATHS_PARAM)
|
||||
{
|
||||
assert(path.is_absolute());
|
||||
assert(path.parent_path() != path);
|
||||
|
||||
AutoCloseFD dirfd = toDescriptor(open(path.parent_path().string().c_str(), O_RDONLY));
|
||||
if (!dirfd) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
throw SysError("opening directory %s", path.parent_path());
|
||||
}
|
||||
|
||||
std::exception_ptr ex;
|
||||
|
||||
_deletePath(dirfd.get(), path, bytesFreed, ex MOUNTEDPATHS_ARG);
|
||||
|
||||
if (ex)
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
|
||||
void deletePath(const std::filesystem::path & path)
|
||||
{
|
||||
uint64_t dummy;
|
||||
deletePath(path, dummy);
|
||||
}
|
||||
|
||||
void createDir(const Path & path, mode_t mode)
|
||||
{
|
||||
if (mkdir(
|
||||
|
|
@ -577,25 +441,6 @@ void createDirs(const std::filesystem::path & path)
|
|||
}
|
||||
}
|
||||
|
||||
void deletePath(const std::filesystem::path & path, uint64_t & bytesFreed)
|
||||
{
|
||||
// Activity act(*logger, lvlDebug, "recursively deleting path '%1%'", path);
|
||||
#ifdef __FreeBSD__
|
||||
std::set<Path> mountedPaths;
|
||||
struct statfs * mntbuf;
|
||||
int count;
|
||||
if ((count = getmntinfo(&mntbuf, MNT_WAIT)) < 0) {
|
||||
throw SysError("getmntinfo");
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
mountedPaths.emplace(mntbuf[i].f_mntonname);
|
||||
}
|
||||
#endif
|
||||
bytesFreed = 0;
|
||||
_deletePath(path, bytesFreed MOUNTEDPATHS_ARG);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
AutoDelete::AutoDelete()
|
||||
|
|
@ -672,11 +517,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)
|
||||
{
|
||||
while (1) {
|
||||
|
|
|
|||
|
|
@ -261,4 +261,14 @@ Descriptor openFileEnsureBeneathNoSymlinks(Descriptor dirFd, const CanonPath & p
|
|||
|
||||
MakeError(EndOfFile, Error);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/**
|
||||
* Windows specific replacement for POSIX `lseek` that operates on a `HANDLE` and not
|
||||
* a file descriptor.
|
||||
*/
|
||||
off_t lseek(Descriptor fd, off_t offset, int whence);
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ struct UnixPathTrait
|
|||
{
|
||||
return path.rfind('/', from);
|
||||
}
|
||||
|
||||
static size_t rootNameLen(StringView)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -83,6 +88,18 @@ struct WindowsPathTrait
|
|||
size_t p2 = path.rfind(preferredSep, from);
|
||||
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>
|
||||
|
|
@ -116,6 +133,11 @@ typename PathDict::String canonPathInner(typename PathDict::StringView remaining
|
|||
typename PathDict::String result;
|
||||
result.reserve(256);
|
||||
|
||||
if (auto rootNameLength = PathDict::rootNameLen(remaining)) {
|
||||
result += remaining.substr(0, rootNameLength); /* Copy drive letter verbatim. */
|
||||
remaining.remove_prefix(rootNameLength);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
||||
/* Skip slashes. */
|
||||
|
|
|
|||
|
|
@ -362,6 +362,8 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix = "nix");
|
|||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "nix/util/nar-accessor.hh"
|
||||
#include "nix/util/file-descriptor.hh"
|
||||
#include "nix/util/archive.hh"
|
||||
|
||||
#include <map>
|
||||
|
|
@ -281,7 +282,7 @@ GetNarBytes seekableGetNarBytes(const Path & path)
|
|||
GetNarBytes seekableGetNarBytes(Descriptor fd)
|
||||
{
|
||||
return [fd](uint64_t offset, uint64_t length) {
|
||||
if (::lseek(fromDescriptorReadOnly(fd), offset, SEEK_SET) == -1)
|
||||
if (lseek(fd, offset, SEEK_SET) == -1)
|
||||
throw SysError("seeking in file");
|
||||
|
||||
std::string buf(length, 0);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "nix/util/serialise.hh"
|
||||
#include "nix/util/file-descriptor.hh"
|
||||
#include "nix/util/compression.hh"
|
||||
#include "nix/util/signals.hh"
|
||||
#include "nix/util/util.hh"
|
||||
|
|
@ -162,11 +163,11 @@ size_t FdSource::readUnbuffered(char * data, size_t len)
|
|||
_good = false;
|
||||
throw SysError("reading from file");
|
||||
}
|
||||
#endif
|
||||
if (n == 0) {
|
||||
_good = false;
|
||||
throw EndOfFile(std::string(*endOfFileError));
|
||||
}
|
||||
#endif
|
||||
read += n;
|
||||
return n;
|
||||
}
|
||||
|
|
@ -207,8 +208,7 @@ void FdSource::restart()
|
|||
throw Error("can't seek to the start of a file");
|
||||
buffer.reset();
|
||||
read = bufPosIn = bufPosOut = 0;
|
||||
int fd_ = fromDescriptorReadOnly(fd);
|
||||
if (lseek(fd_, 0, SEEK_SET) == -1)
|
||||
if (lseek(fd, 0, SEEK_SET) == -1)
|
||||
throw SysError("seeking to the start of a file");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "nix/util/file-system.hh"
|
||||
#include "nix/util/environment-variables.hh"
|
||||
#include "nix/util/signals.hh"
|
||||
#include "nix/util/util.hh"
|
||||
|
||||
#include "util-unix-config-private.hh"
|
||||
|
||||
|
|
@ -19,6 +22,11 @@ Descriptor openDirectory(const std::filesystem::path & path)
|
|||
return open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
}
|
||||
|
||||
std::filesystem::path defaultTempDir()
|
||||
{
|
||||
return getEnvNonEmpty("TMPDIR").value_or("/tmp");
|
||||
}
|
||||
|
||||
void setWriteTime(
|
||||
const std::filesystem::path & path, time_t accessedTime, time_t modificationTime, std::optional<bool> optIsSymlink)
|
||||
{
|
||||
|
|
@ -66,4 +74,154 @@ void setWriteTime(
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
# define MOUNTEDPATHS_PARAM , std::set<Path> & mountedPaths
|
||||
# define MOUNTEDPATHS_ARG , mountedPaths
|
||||
#else
|
||||
# define MOUNTEDPATHS_PARAM
|
||||
# define MOUNTEDPATHS_ARG
|
||||
#endif
|
||||
|
||||
static void _deletePath(
|
||||
Descriptor parentfd,
|
||||
const std::filesystem::path & path,
|
||||
uint64_t & bytesFreed,
|
||||
std::exception_ptr & ex MOUNTEDPATHS_PARAM)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
checkInterrupt();
|
||||
|
||||
# ifdef __FreeBSD__
|
||||
// In case of emergency (unmount fails for some reason) not recurse into mountpoints.
|
||||
// This prevents us from tearing up the nullfs-mounted nix store.
|
||||
if (mountedPaths.find(path) != mountedPaths.end()) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
std::string name(path.filename());
|
||||
assert(name != "." && name != ".." && !name.empty());
|
||||
|
||||
struct stat st;
|
||||
if (fstatat(parentfd, name.c_str(), &st, AT_SYMLINK_NOFOLLOW) == -1) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
throw SysError("getting status of %1%", path);
|
||||
}
|
||||
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
/* We are about to delete a file. Will it likely free space? */
|
||||
|
||||
switch (st.st_nlink) {
|
||||
/* Yes: last link. */
|
||||
case 1:
|
||||
bytesFreed += st.st_size;
|
||||
break;
|
||||
/* Maybe: yes, if 'auto-optimise-store' or manual optimisation
|
||||
was performed. Instead of checking for real let's assume
|
||||
it's an optimised file and space will be freed.
|
||||
|
||||
In worst case we will double count on freed space for files
|
||||
with exactly two hardlinks for unoptimised packages.
|
||||
*/
|
||||
case 2:
|
||||
bytesFreed += st.st_size;
|
||||
break;
|
||||
/* No: 3+ links. */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* Make the directory accessible. */
|
||||
const auto PERM_MASK = S_IRUSR | S_IWUSR | S_IXUSR;
|
||||
if ((st.st_mode & PERM_MASK) != PERM_MASK) {
|
||||
if (fchmodat(parentfd, name.c_str(), st.st_mode | PERM_MASK, 0) == -1)
|
||||
throw SysError("chmod %1%", path);
|
||||
}
|
||||
|
||||
int fd = openat(parentfd, name.c_str(), O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
|
||||
if (fd == -1)
|
||||
throw SysError("opening directory %1%", path);
|
||||
AutoCloseDir dir(fdopendir(fd));
|
||||
if (!dir)
|
||||
throw SysError("opening directory %1%", path);
|
||||
|
||||
struct dirent * dirent;
|
||||
while (errno = 0, dirent = readdir(dir.get())) { /* sic */
|
||||
checkInterrupt();
|
||||
std::string childName = dirent->d_name;
|
||||
if (childName == "." || childName == "..")
|
||||
continue;
|
||||
_deletePath(dirfd(dir.get()), path / childName, bytesFreed, ex MOUNTEDPATHS_ARG);
|
||||
}
|
||||
if (errno)
|
||||
throw SysError("reading directory %1%", path);
|
||||
}
|
||||
|
||||
int flags = S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0;
|
||||
if (unlinkat(parentfd, name.c_str(), flags) == -1) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
try {
|
||||
throw SysError("cannot unlink %1%", path);
|
||||
} catch (...) {
|
||||
if (!ex)
|
||||
ex = std::current_exception();
|
||||
else
|
||||
ignoreExceptionExceptInterrupt();
|
||||
}
|
||||
}
|
||||
#else
|
||||
// TODO implement
|
||||
throw UnimplementedError("_deletePath");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _deletePath(const std::filesystem::path & path, uint64_t & bytesFreed MOUNTEDPATHS_PARAM)
|
||||
{
|
||||
assert(path.is_absolute());
|
||||
assert(path.parent_path() != path);
|
||||
|
||||
AutoCloseFD dirfd = toDescriptor(open(path.parent_path().string().c_str(), O_RDONLY));
|
||||
if (!dirfd) {
|
||||
if (errno == ENOENT)
|
||||
return;
|
||||
throw SysError("opening directory %s", path.parent_path());
|
||||
}
|
||||
|
||||
std::exception_ptr ex;
|
||||
|
||||
_deletePath(dirfd.get(), path, bytesFreed, ex MOUNTEDPATHS_ARG);
|
||||
|
||||
if (ex)
|
||||
std::rethrow_exception(ex);
|
||||
}
|
||||
|
||||
void deletePath(const std::filesystem::path & path)
|
||||
{
|
||||
uint64_t dummy;
|
||||
deletePath(path, dummy);
|
||||
}
|
||||
|
||||
void deletePath(const std::filesystem::path & path, uint64_t & bytesFreed)
|
||||
{
|
||||
// Activity act(*logger, lvlDebug, "recursively deleting path '%1%'", path);
|
||||
#ifdef __FreeBSD__
|
||||
std::set<Path> mountedPaths;
|
||||
struct statfs * mntbuf;
|
||||
int count;
|
||||
if ((count = getmntinfo(&mntbuf, MNT_WAIT)) < 0) {
|
||||
throw SysError("getmntinfo");
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
mountedPaths.emplace(mntbuf[i].f_mntonname);
|
||||
}
|
||||
#endif
|
||||
bytesFreed = 0;
|
||||
_deletePath(path, bytesFreed MOUNTEDPATHS_ARG);
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@
|
|||
#include "nix/util/windows-error.hh"
|
||||
#include "nix/util/file-path.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <fileapi.h>
|
||||
# include <error.h>
|
||||
# include <namedpipeapi.h>
|
||||
# include <namedpipeapi.h>
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#include <fileapi.h>
|
||||
#include <error.h>
|
||||
#include <namedpipeapi.h>
|
||||
#include <namedpipeapi.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
@ -46,16 +45,16 @@ void writeFull(HANDLE handle, std::string_view s, bool allowInterrupts)
|
|||
if (allowInterrupts)
|
||||
checkInterrupt();
|
||||
DWORD res;
|
||||
# if _WIN32_WINNT >= 0x0600
|
||||
#if _WIN32_WINNT >= 0x0600
|
||||
auto path = handleToPath(handle); // debug; do it before because handleToPath changes lasterror
|
||||
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
|
||||
throw WinError("writing to file %1%:%2%", handle, path);
|
||||
}
|
||||
# else
|
||||
#else
|
||||
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
|
||||
throw WinError("writing to file %1%", handle);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
if (res > 0)
|
||||
s.remove_prefix(res);
|
||||
}
|
||||
|
|
@ -120,7 +119,7 @@ void Pipe::create()
|
|||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
# if _WIN32_WINNT >= 0x0600
|
||||
#if _WIN32_WINNT >= 0x0600
|
||||
|
||||
std::wstring windows::handleToFileName(HANDLE handle)
|
||||
{
|
||||
|
|
@ -149,7 +148,37 @@ Path windows::handleToPath(HANDLE handle)
|
|||
return os_string_to_string(handleToFileName(handle));
|
||||
}
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
off_t lseek(HANDLE h, off_t offset, int whence)
|
||||
{
|
||||
DWORD method;
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
method = FILE_BEGIN;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
method = FILE_CURRENT;
|
||||
break;
|
||||
case SEEK_END:
|
||||
method = FILE_END;
|
||||
break;
|
||||
default:
|
||||
throw Error("lseek: invalid whence %d", whence);
|
||||
}
|
||||
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = offset;
|
||||
LARGE_INTEGER newPos;
|
||||
|
||||
if (!SetFilePointerEx(h, li, &newPos, method)) {
|
||||
/* Convert to a POSIX error, since caller code works with this as if it were
|
||||
a POSIX lseek. */
|
||||
errno = std::error_code(GetLastError(), std::system_category()).default_error_condition().value();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return newPos.QuadPart;
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
#include "nix/util/file-system.hh"
|
||||
#include "nix/util/windows-error.hh"
|
||||
#include "nix/util/logging.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace nix {
|
||||
|
||||
using namespace nix::windows;
|
||||
|
||||
void setWriteTime(
|
||||
const std::filesystem::path & path, time_t accessedTime, time_t modificationTime, std::optional<bool> optIsSymlink)
|
||||
{
|
||||
|
|
@ -28,5 +30,27 @@ Descriptor openDirectory(const std::filesystem::path & path)
|
|||
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);
|
||||
}
|
||||
|
||||
void deletePath(const std::filesystem::path & path)
|
||||
{
|
||||
std::error_code ec;
|
||||
std::filesystem::remove_all(path, ec);
|
||||
if (ec && ec != std::errc::no_such_file_or_directory)
|
||||
throw SysError(ec.default_error_condition().value(), "recursively deleting %1%", path);
|
||||
}
|
||||
|
||||
void deletePath(const std::filesystem::path & path, uint64_t & bytesFreed)
|
||||
{
|
||||
bytesFreed = 0;
|
||||
deletePath(path);
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue