mirror of
https://github.com/NixOS/nix.git
synced 2025-12-23 01:11:07 +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)
|
TEST(createAnonymousTempFile, works)
|
||||||
{
|
{
|
||||||
auto fd = createAnonymousTempFile();
|
auto fd = createAnonymousTempFile();
|
||||||
auto fd_ = fromDescriptorReadOnly(fd.get());
|
|
||||||
writeFull(fd.get(), "test");
|
writeFull(fd.get(), "test");
|
||||||
lseek(fd_, 0, SEEK_SET);
|
lseek(fd.get(), 0, SEEK_SET);
|
||||||
FdSource source{fd.get()};
|
FdSource source{fd.get()};
|
||||||
EXPECT_EQ(source.drain(), "test");
|
EXPECT_EQ(source.drain(), "test");
|
||||||
lseek(fd_, 0, SEEK_END);
|
lseek(fd.get(), 0, SEEK_END);
|
||||||
writeFull(fd.get(), "test");
|
writeFull(fd.get(), "test");
|
||||||
lseek(fd_, 0, SEEK_SET);
|
lseek(fd.get(), 0, SEEK_SET);
|
||||||
EXPECT_EQ(source.drain(), "testtest");
|
EXPECT_EQ(source.drain(), "testtest");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,9 +405,8 @@ TEST(createAnonymousTempFile, works)
|
||||||
TEST(FdSource, restartWorks)
|
TEST(FdSource, restartWorks)
|
||||||
{
|
{
|
||||||
auto fd = createAnonymousTempFile();
|
auto fd = createAnonymousTempFile();
|
||||||
auto fd_ = fromDescriptorReadOnly(fd.get());
|
|
||||||
writeFull(fd.get(), "hello world");
|
writeFull(fd.get(), "hello world");
|
||||||
lseek(fd_, 0, SEEK_SET);
|
lseek(fd.get(), 0, SEEK_SET);
|
||||||
FdSource source{fd.get()};
|
FdSource source{fd.get()};
|
||||||
EXPECT_EQ(source.drain(), "hello world");
|
EXPECT_EQ(source.drain(), "hello world");
|
||||||
source.restart();
|
source.restart();
|
||||||
|
|
|
||||||
|
|
@ -261,4 +261,14 @@ Descriptor openFileEnsureBeneathNoSymlinks(Descriptor dirFd, const CanonPath & p
|
||||||
|
|
||||||
MakeError(EndOfFile, Error);
|
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
|
} // namespace nix
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "nix/util/nar-accessor.hh"
|
#include "nix/util/nar-accessor.hh"
|
||||||
|
#include "nix/util/file-descriptor.hh"
|
||||||
#include "nix/util/archive.hh"
|
#include "nix/util/archive.hh"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
@ -281,7 +282,7 @@ GetNarBytes seekableGetNarBytes(const Path & path)
|
||||||
GetNarBytes seekableGetNarBytes(Descriptor fd)
|
GetNarBytes seekableGetNarBytes(Descriptor fd)
|
||||||
{
|
{
|
||||||
return [fd](uint64_t offset, uint64_t length) {
|
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");
|
throw SysError("seeking in file");
|
||||||
|
|
||||||
std::string buf(length, 0);
|
std::string buf(length, 0);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "nix/util/serialise.hh"
|
#include "nix/util/serialise.hh"
|
||||||
|
#include "nix/util/file-descriptor.hh"
|
||||||
#include "nix/util/compression.hh"
|
#include "nix/util/compression.hh"
|
||||||
#include "nix/util/signals.hh"
|
#include "nix/util/signals.hh"
|
||||||
#include "nix/util/util.hh"
|
#include "nix/util/util.hh"
|
||||||
|
|
@ -207,8 +208,7 @@ void FdSource::restart()
|
||||||
throw Error("can't seek to the start of a file");
|
throw Error("can't seek to the start of a file");
|
||||||
buffer.reset();
|
buffer.reset();
|
||||||
read = bufPosIn = bufPosOut = 0;
|
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");
|
throw SysError("seeking to the start of a file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,12 @@
|
||||||
#include "nix/util/windows-error.hh"
|
#include "nix/util/windows-error.hh"
|
||||||
#include "nix/util/file-path.hh"
|
#include "nix/util/file-path.hh"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#include <fileapi.h>
|
||||||
# include <fileapi.h>
|
#include <error.h>
|
||||||
# include <error.h>
|
#include <namedpipeapi.h>
|
||||||
# include <namedpipeapi.h>
|
#include <namedpipeapi.h>
|
||||||
# include <namedpipeapi.h>
|
#define WIN32_LEAN_AND_MEAN
|
||||||
# define WIN32_LEAN_AND_MEAN
|
#include <windows.h>
|
||||||
# include <windows.h>
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
@ -46,16 +45,16 @@ void writeFull(HANDLE handle, std::string_view s, bool allowInterrupts)
|
||||||
if (allowInterrupts)
|
if (allowInterrupts)
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
DWORD res;
|
DWORD res;
|
||||||
# if _WIN32_WINNT >= 0x0600
|
#if _WIN32_WINNT >= 0x0600
|
||||||
auto path = handleToPath(handle); // debug; do it before because handleToPath changes lasterror
|
auto path = handleToPath(handle); // debug; do it before because handleToPath changes lasterror
|
||||||
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
|
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
|
||||||
throw WinError("writing to file %1%:%2%", handle, path);
|
throw WinError("writing to file %1%:%2%", handle, path);
|
||||||
}
|
}
|
||||||
# else
|
#else
|
||||||
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
|
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
|
||||||
throw WinError("writing to file %1%", handle);
|
throw WinError("writing to file %1%", handle);
|
||||||
}
|
}
|
||||||
# endif
|
#endif
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
s.remove_prefix(res);
|
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)
|
std::wstring windows::handleToFileName(HANDLE handle)
|
||||||
{
|
{
|
||||||
|
|
@ -149,7 +148,37 @@ Path windows::handleToPath(HANDLE handle)
|
||||||
return os_string_to_string(handleToFileName(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
|
} // namespace nix
|
||||||
#endif
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue