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:
parent
f274a7273a
commit
89dc57f6aa
5 changed files with 60 additions and 22 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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue