Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 30 additions & 16 deletions src/libstore/windows/pathlocks.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include "nix/util/file-system.hh"
#include "nix/util/logging.hh"
#include "nix/store/pathlocks.hh"
#include "nix/util/signals.hh"
#include "nix/util/util.hh"
#include "nix/util/windows-environment.hh"

#ifdef _WIN32
# include <errhandlingapi.h>
Expand Down Expand Up @@ -51,49 +53,61 @@ AutoCloseFD openLockFile(const std::filesystem::path & path, bool create)
return desc;
}

/**
* Throw a WinError, or if running under Wine, just warn and return true.
* Wine has incomplete file locking support, so we degrade gracefully.
*/
template<typename... Args>
static bool warnOrThrowWine(DWORD lastError, const std::string & fs, const Args &... args)
{
if (isWine()) {
warn(fs + ": %s (ignored under Wine)", args..., lastError);
return true;
}
throw WinError(lastError, fs, args...);
}

bool lockFile(Descriptor desc, LockType lockType, bool wait)
{
switch (lockType) {
case ltNone: {
OVERLAPPED ov = {0};
if (!UnlockFileEx(desc, 0, 2, 0, &ov)) {
WinError winError("Failed to unlock file desc %s", desc);
throw winError;
}
if (!UnlockFileEx(desc, 0, 2, 0, &ov))
return warnOrThrowWine(GetLastError(), "Failed to unlock file %s", PathFmt(descriptorToPath(desc)));
return true;
}
case ltRead: {
OVERLAPPED ov = {0};
if (!LockFileEx(desc, wait ? 0 : LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &ov)) {
WinError winError("Failed to lock file desc %s", desc);
if (winError.lastError == ERROR_LOCK_VIOLATION)
auto lastError = GetLastError();
if (lastError == ERROR_LOCK_VIOLATION)
return false;
throw winError;
return warnOrThrowWine(lastError, "Failed to lock file %s", PathFmt(descriptorToPath(desc)));
}

ov.Offset = 1;
if (!UnlockFileEx(desc, 0, 1, 0, &ov)) {
WinError winError("Failed to unlock file desc %s", desc);
if (winError.lastError != ERROR_NOT_LOCKED)
throw winError;
auto lastError = GetLastError();
if (lastError != ERROR_NOT_LOCKED)
return warnOrThrowWine(lastError, "Failed to unlock file %s", PathFmt(descriptorToPath(desc)));
}
return true;
}
case ltWrite: {
OVERLAPPED ov = {0};
ov.Offset = 1;
if (!LockFileEx(desc, LOCKFILE_EXCLUSIVE_LOCK | (wait ? 0 : LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ov)) {
WinError winError("Failed to lock file desc %s", desc);
if (winError.lastError == ERROR_LOCK_VIOLATION)
auto lastError = GetLastError();
if (lastError == ERROR_LOCK_VIOLATION)
return false;
throw winError;
return warnOrThrowWine(lastError, "Failed to lock file %s", PathFmt(descriptorToPath(desc)));
}

ov.Offset = 0;
if (!UnlockFileEx(desc, 0, 1, 0, &ov)) {
WinError winError("Failed to unlock file desc %s", desc);
if (winError.lastError != ERROR_NOT_LOCKED)
throw winError;
auto lastError = GetLastError();
if (lastError != ERROR_NOT_LOCKED)
return warnOrThrowWine(lastError, "Failed to unlock file %s", PathFmt(descriptorToPath(desc)));
}
return true;
}
Expand Down
1 change: 1 addition & 0 deletions src/libutil/windows/include/nix/util/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ include_dirs += include_directories('../..')
headers += files(
'signals-impl.hh',
'windows-async-pipe.hh',
'windows-environment.hh',
'windows-known-folders.hh',
)
12 changes: 12 additions & 0 deletions src/libutil/windows/include/nix/util/windows-environment.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

///@file

namespace nix::windows {

/**
* Check if the current process is running under Wine.
*/
bool isWine();

} // namespace nix::windows
1 change: 1 addition & 0 deletions src/libutil/windows/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ sources += files(
'processes.cc',
'users.cc',
'windows-async-pipe.cc',
'windows-environment.cc',
'windows-error.cc',
)

Expand Down
14 changes: 14 additions & 0 deletions src/libutil/windows/windows-environment.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "nix/util/windows-environment.hh"

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

namespace nix::windows {

bool isWine()
{
HMODULE hntdll = GetModuleHandle("ntdll.dll");
return GetProcAddress(hntdll, "wine_get_version") != nullptr;
}

} // namespace nix::windows
Loading