nix-super/src/libutil/windows/file-descriptor.cc

151 lines
3.9 KiB
C++
Raw Normal View History

#include "file-system.hh"
#include "signals.hh"
#include "finally.hh"
#include "serialise.hh"
#include "windows-error.hh"
#include "file-path.hh"
#include <fileapi.h>
#include <error.h>
#include <namedpipeapi.h>
#include <namedpipeapi.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace nix {
using namespace nix::windows;
std::string readFile(HANDLE handle)
{
LARGE_INTEGER li;
if (!GetFileSizeEx(handle, &li))
throw WinError("%s:%d statting file", __FILE__, __LINE__);
return drainFD(handle, true, li.QuadPart);
}
void readFull(HANDLE handle, char * buf, size_t count)
{
while (count) {
checkInterrupt();
DWORD res;
if (!ReadFile(handle, (char *) buf, count, &res, NULL))
throw WinError("%s:%d reading from file", __FILE__, __LINE__);
if (res == 0) throw EndOfFile("unexpected end-of-file");
count -= res;
buf += res;
}
}
void writeFull(HANDLE handle, std::string_view s, bool allowInterrupts)
{
while (!s.empty()) {
if (allowInterrupts) checkInterrupt();
DWORD res;
#if _WIN32_WINNT >= 0x0600
auto path = handleToPath(handle); // debug; do it before becuase handleToPath changes lasterror
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
throw WinError("writing to file %1%:%2%", handle, path);
}
#else
if (!WriteFile(handle, s.data(), s.size(), &res, NULL)) {
throw WinError("writing to file %1%", handle);
}
#endif
if (res > 0)
s.remove_prefix(res);
}
}
std::string readLine(HANDLE handle)
{
std::string s;
while (1) {
checkInterrupt();
char ch;
// FIXME: inefficient
DWORD rd;
if (!ReadFile(handle, &ch, 1, &rd, NULL)) {
throw WinError("reading a line");
} else if (rd == 0)
throw EndOfFile("unexpected EOF reading a line");
else {
if (ch == '\n') return s;
s += ch;
}
}
}
void drainFD(HANDLE handle, Sink & sink/*, bool block*/)
{
std::vector<unsigned char> buf(64 * 1024);
while (1) {
checkInterrupt();
DWORD rd;
if (!ReadFile(handle, buf.data(), buf.size(), &rd, NULL)) {
WinError winError("%s:%d reading from handle %p", __FILE__, __LINE__, handle);
if (winError.lastError == ERROR_BROKEN_PIPE)
break;
throw winError;
}
else if (rd == 0) break;
sink({(char *) buf.data(), (size_t) rd});
}
}
//////////////////////////////////////////////////////////////////////
void Pipe::create()
{
SECURITY_ATTRIBUTES saAttr = {0};
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.lpSecurityDescriptor = NULL;
saAttr.bInheritHandle = TRUE;
HANDLE hReadPipe, hWritePipe;
if (!CreatePipe(&hReadPipe, &hWritePipe, &saAttr, 0))
throw WinError("CreatePipe");
readSide = hReadPipe;
writeSide = hWritePipe;
}
//////////////////////////////////////////////////////////////////////
#if _WIN32_WINNT >= 0x0600
std::wstring windows::handleToFileName(HANDLE handle) {
std::vector<wchar_t> buf(0x100);
DWORD dw = GetFinalPathNameByHandleW(handle, buf.data(), buf.size(), FILE_NAME_OPENED);
if (dw == 0) {
if (handle == GetStdHandle(STD_INPUT_HANDLE )) return L"<stdin>";
if (handle == GetStdHandle(STD_OUTPUT_HANDLE)) return L"<stdout>";
if (handle == GetStdHandle(STD_ERROR_HANDLE )) return L"<stderr>";
return (boost::wformat(L"<unnnamed handle %X>") % handle).str();
}
if (dw > buf.size()) {
buf.resize(dw);
if (GetFinalPathNameByHandleW(handle, buf.data(), buf.size(), FILE_NAME_OPENED) != dw-1)
throw WinError("GetFinalPathNameByHandleW");
dw -= 1;
}
return std::wstring(buf.data(), dw);
}
Path windows::handleToPath(HANDLE handle) {
return os_string_to_string(handleToFileName(handle));
}
#endif
}