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

libutil: Implement HANDLE-based lseek for Windows

For windows we should live fully in the HANDLE land instead
of converting back-n-forth (which sometimes is destructive).
Using native API is much better for this.
This commit is contained in:
Sergei Zimmerman 2025-12-17 23:47:53 +03:00
parent f274a7273a
commit 89dc57f6aa
No known key found for this signature in database
5 changed files with 60 additions and 22 deletions

View file

@ -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();

View file

@ -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

View file

@ -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);

View file

@ -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"
@ -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");
}

View file

@ -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