blob: 328182148b501a15cba011e98b819988dc9159d9 [file] [log] [blame] [edit]
//===- llvm/Support/Windows/MSFileSystemBasic.cpp DXComplier Impl *- C++
//-*-===//
///////////////////////////////////////////////////////////////////////////////
// //
// MSFileSystemBasic.cpp //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// This file implements the DXCompiler specific implementation of the Path
// API.//
// //
///////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
#include "dxc/Support/WinIncludes.h"
#include <assert.h>
#include <d3dcommon.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <new>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unordered_map>
#include "dxc/Support/Global.h"
#include "llvm/Support/MSFileSystem.h"
#include "dxc/dxcapi.internal.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
// Externally visible functions.
/// <summary>Creates an implementation based on IDxcSystemAccess.</summary>
HRESULT
CreateMSFileSystemForIface(IUnknown *pService,
::llvm::sys::fs::MSFileSystem **pResult) throw();
/// <summary>Creates an implementation with no access to system
/// resources.</summary>
HRESULT
CreateMSFileSystemBlocked(::llvm::sys::fs::MSFileSystem **pResult) throw();
///////////////////////////////////////////////////////////////////////////////////////////////////
// Helper functions.
static DWORD WIN32_FROM_HRESULT(HRESULT hr) {
if (SUCCEEDED(hr))
return ERROR_SUCCESS;
if ((HRESULT)(hr & 0xFFFF0000) ==
MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, 0)) {
// Could have come from many values, but we choose this one
return HRESULT_CODE(hr);
}
if (hr == E_OUTOFMEMORY)
return ERROR_OUTOFMEMORY;
if (hr == E_NOTIMPL)
return ERROR_CALL_NOT_IMPLEMENTED;
return ERROR_FUNCTION_FAILED;
}
static HRESULT CopyStatStg(const STATSTG *statStg,
LPWIN32_FIND_DATAW lpFindFileData) {
HRESULT hr = S_OK;
lpFindFileData->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
lpFindFileData->ftCreationTime = statStg->ctime;
lpFindFileData->ftLastAccessTime = statStg->atime;
lpFindFileData->ftLastWriteTime = statStg->mtime;
lpFindFileData->nFileSizeLow = statStg->cbSize.LowPart;
lpFindFileData->nFileSizeHigh = statStg->cbSize.HighPart;
if (statStg->pwcsName != nullptr) {
IFC(StringCchCopyW(lpFindFileData->cFileName,
_countof(lpFindFileData->cFileName), statStg->pwcsName));
}
Cleanup:
return hr;
}
static void ClearStatStg(STATSTG *statStg) {
DXASSERT_NOMSG(statStg != nullptr);
if (statStg->pwcsName != nullptr) {
CoTaskMemFree(statStg->pwcsName);
statStg->pwcsName = nullptr;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// IDxcSystemAccess-based MSFileSystem implementation.
struct MSFileSystemHandle {
enum MSFileSystemHandleKind {
MSFileSystemHandleKind_FindHandle,
MSFileSystemHandleKind_FileHandle,
MSFileSystemHandleKind_FileMappingHandle
};
MSFileSystemHandleKind kind;
CComPtr<IUnknown>
storage; // For a file handle, the stream or directory handle.
// For a find handle, the IEnumSTATSTG associated.
CComPtr<IStream>
stream; // For a file or console file handle, the stream interface.
int fd; // For a file handle, its file descriptor.
explicit MSFileSystemHandle(int knownFD)
: kind(MSFileSystemHandleKind_FileHandle), fd(knownFD) {}
explicit MSFileSystemHandle(IUnknown *pMapping)
: kind(MSFileSystemHandleKind_FileMappingHandle), storage(pMapping),
fd(0) {}
MSFileSystemHandle(IUnknown *pStorage, IStream *pStream)
: kind(MSFileSystemHandleKind_FileHandle), storage(pStorage),
stream(pStream), fd(0) {}
explicit MSFileSystemHandle(IEnumSTATSTG *pEnumSTATG)
: kind(MSFileSystemHandleKind_FindHandle), storage(pEnumSTATG) {}
MSFileSystemHandle(MSFileSystemHandle &&other) {
kind = other.kind;
storage.p = other.storage.Detach();
stream.p = other.stream.Detach();
}
HANDLE GetHandle() const { return (HANDLE)this; }
IEnumSTATSTG *GetEnumStatStg() {
DXASSERT(kind == MSFileSystemHandleKind_FindHandle,
"otherwise caller didn't check");
return (IEnumSTATSTG *)storage.p;
}
};
namespace llvm {
namespace sys {
namespace fs {
class MSFileSystemForIface : public MSFileSystem {
private:
CComPtr<IDxcSystemAccess> m_system;
typedef std::unordered_multimap<LPCVOID, ID3D10Blob *> TViewMap;
TViewMap m_mappingViews;
MSFileSystemHandle m_knownHandle0;
MSFileSystemHandle m_knownHandle1;
MSFileSystemHandle m_knownHandle2;
HRESULT AddFindHandle(IEnumSTATSTG *enumStatStg, HANDLE *pResult) throw();
HRESULT AddFileHandle(IUnknown *storage, IStream *stream,
HANDLE *pResult) throw();
HRESULT AddMappingHandle(IUnknown *mapping, HANDLE *pResult) throw();
HRESULT AddMappingView(ID3D10Blob *blob) throw();
HRESULT EnsureFDAvailable(int fd);
HANDLE GetHandleForFD(int fd) throw();
void GetFindHandle(HANDLE findHandle, IEnumSTATSTG **enumStatStg) throw();
int GetHandleFD(HANDLE fileHandle) throw();
void GetHandleMapping(HANDLE fileHandle, IUnknown **pResult) throw();
void GetHandleStorage(HANDLE fileHandle, IUnknown **pResult) throw();
void GetHandleStream(HANDLE fileHandle, IStream **pResult) throw();
void CloseInternalHandle(HANDLE findHandle) throw();
void RemoveMappingView(LPCVOID address) throw();
public:
MSFileSystemForIface(IDxcSystemAccess *access);
virtual BOOL
FindNextFileW(HANDLE hFindFile,
LPWIN32_FIND_DATAW lpFindFileData) throw() override;
virtual HANDLE
FindFirstFileW(LPCWSTR lpFileName,
LPWIN32_FIND_DATAW lpFindFileData) throw() override;
virtual void FindClose(HANDLE findHandle) throw() override;
virtual HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes) throw() override;
virtual BOOL SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime,
const FILETIME *lpLastAccessTime,
const FILETIME *lpLastWriteTime) throw() override;
virtual BOOL GetFileInformationByHandle(
HANDLE hFile,
LPBY_HANDLE_FILE_INFORMATION lpFileInformation) throw() override;
virtual DWORD GetFileType(HANDLE hFile) throw() override;
virtual BOOL CreateHardLinkW(LPCWSTR lpFileName,
LPCWSTR lpExistingFileName) throw() override;
virtual BOOL MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName,
DWORD dwFlags) throw() override;
virtual DWORD GetFileAttributesW(LPCWSTR lpFileName) throw() override;
virtual BOOL CloseHandle(HANDLE hObject) throw() override;
virtual BOOL DeleteFileW(LPCWSTR lpFileName) throw() override;
virtual BOOL RemoveDirectoryW(LPCWSTR lpFileName) throw() override;
virtual BOOL CreateDirectoryW(LPCWSTR lpPathName) throw() override;
virtual DWORD GetCurrentDirectoryW(DWORD nBufferLength,
LPWSTR lpBuffer) throw() override;
virtual DWORD GetMainModuleFileNameW(LPWSTR lpFilename,
DWORD nSize) throw() override;
virtual DWORD GetTempPathW(DWORD nBufferLength,
LPWSTR lpBuffer) throw() override;
virtual BOOLEAN CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName,
LPCWSTR lpTargetFileName,
DWORD dwFlags) throw() override;
virtual bool SupportsCreateSymbolicLink() throw() override;
virtual BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead) throw() override;
virtual HANDLE CreateFileMappingW(HANDLE hFile, DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow) throw() override;
virtual LPVOID MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess,
DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow,
SIZE_T dwNumberOfBytesToMap) throw() override;
virtual BOOL UnmapViewOfFile(LPCVOID lpBaseAddress) throw() override;
// Console APIs.
virtual bool FileDescriptorIsDisplayed(int fd) throw() override;
virtual unsigned GetColumnCount(DWORD nStdHandle) throw() override;
virtual unsigned GetConsoleOutputTextAttributes() throw() override;
virtual void
SetConsoleOutputTextAttributes(unsigned attributes) throw() override;
virtual void ResetConsoleOutputTextAttributes() throw() override;
// CRT APIs.
virtual int open_osfhandle(intptr_t osfhandle, int flags) throw() override;
virtual intptr_t get_osfhandle(int fd) throw() override;
virtual int close(int fd) throw() override;
virtual long lseek(int fd, long offset, int origin) throw() override;
virtual int setmode(int fd, int mode) throw() override;
virtual errno_t resize_file(LPCWSTR path, uint64_t size) throw() override;
virtual int Read(int fd, void *buffer, unsigned int count) throw() override;
virtual int Write(int fd, const void *buffer,
unsigned int count) throw() override;
#ifndef _WIN32
virtual int Open(const char *lpFileName, int flags,
mode_t mode) throw() override;
virtual int Stat(const char *lpFileName,
struct stat *Status) throw() override;
virtual int Fstat(int FD, struct stat *Status) throw() override;
#endif
};
MSFileSystemForIface::MSFileSystemForIface(IDxcSystemAccess *systemAccess)
: m_system(systemAccess), m_knownHandle0(0), m_knownHandle1(1),
m_knownHandle2(2) {}
HRESULT MSFileSystemForIface::AddMappingHandle(IUnknown *mapping,
HANDLE *pResult) throw() {
DXASSERT_NOMSG(mapping != nullptr);
DXASSERT_NOMSG(pResult != nullptr);
HRESULT hr = S_OK;
MSFileSystemHandle *handle = nullptr;
*pResult = INVALID_HANDLE_VALUE;
handle = new (std::nothrow) MSFileSystemHandle(mapping);
IFCOOM(handle);
*pResult = handle->GetHandle();
Cleanup:
return hr;
}
HRESULT MSFileSystemForIface::AddMappingView(ID3D10Blob *blob) throw() {
DXASSERT_NOMSG(blob != nullptr);
LPVOID address = blob->GetBufferPointer();
try {
m_mappingViews.insert(std::pair<LPVOID, ID3D10Blob *>(address, blob));
} catch (std::bad_alloc &) {
return E_OUTOFMEMORY;
}
blob->AddRef();
return S_OK;
}
HRESULT MSFileSystemForIface::AddFindHandle(IEnumSTATSTG *enumStatStg,
HANDLE *pResult) throw() {
DXASSERT_NOMSG(enumStatStg != nullptr);
DXASSERT_NOMSG(pResult != nullptr);
HRESULT hr = S_OK;
MSFileSystemHandle *handle = nullptr;
*pResult = INVALID_HANDLE_VALUE;
handle = new (std::nothrow) MSFileSystemHandle(enumStatStg);
IFCOOM(handle);
*pResult = handle->GetHandle();
Cleanup:
return hr;
}
HRESULT MSFileSystemForIface::AddFileHandle(IUnknown *storage, IStream *stream,
HANDLE *pResult) throw() {
DXASSERT_NOMSG(storage != nullptr);
DXASSERT_NOMSG(pResult != nullptr);
HRESULT hr = S_OK;
MSFileSystemHandle *handle = nullptr;
*pResult = INVALID_HANDLE_VALUE;
handle = new (std::nothrow) MSFileSystemHandle(storage, stream);
IFCOOM(handle);
*pResult = handle->GetHandle();
Cleanup:
return hr;
}
void MSFileSystemForIface::CloseInternalHandle(HANDLE handle) throw() {
DXASSERT_NOMSG(handle != nullptr);
DXASSERT_NOMSG(handle != INVALID_HANDLE_VALUE);
MSFileSystemHandle *fsHandle = reinterpret_cast<MSFileSystemHandle *>(handle);
if (fsHandle == &m_knownHandle0 || fsHandle == &m_knownHandle1 ||
fsHandle == &m_knownHandle2) {
fsHandle->stream.Release();
fsHandle->storage.Release();
} else {
delete fsHandle;
}
}
void MSFileSystemForIface::RemoveMappingView(LPCVOID address) throw() {
TViewMap::iterator i = m_mappingViews.find(address);
DXASSERT(i != m_mappingViews.end(), "otherwise pointer to view isn't in map");
DXASSERT(i->second != nullptr,
"otherwise blob is null and should not have been added");
i->second->Release();
m_mappingViews.erase(i);
}
void MSFileSystemForIface::GetFindHandle(HANDLE findHandle,
IEnumSTATSTG **enumStatStg) throw() {
DXASSERT_NOMSG(findHandle != nullptr);
DXASSERT_NOMSG(enumStatStg != nullptr);
MSFileSystemHandle *fsHandle =
reinterpret_cast<MSFileSystemHandle *>(findHandle);
DXASSERT(fsHandle->kind ==
MSFileSystemHandle::MSFileSystemHandleKind_FindHandle,
"otherwise caller is passing wrong handle to API");
*enumStatStg = fsHandle->GetEnumStatStg();
DXASSERT(*enumStatStg != nullptr,
"otherwise it should not have been added to handle entry");
(*enumStatStg)->AddRef();
}
int MSFileSystemForIface::GetHandleFD(HANDLE fileHandle) throw() {
DXASSERT_NOMSG(fileHandle != nullptr);
MSFileSystemHandle *fsHandle =
reinterpret_cast<MSFileSystemHandle *>(fileHandle);
DXASSERT(fsHandle->kind ==
MSFileSystemHandle::MSFileSystemHandleKind_FileHandle,
"otherwise caller is passing wrong handle to API");
return fsHandle->fd;
}
void MSFileSystemForIface::GetHandleMapping(HANDLE mapping,
IUnknown **pResult) throw() {
DXASSERT_NOMSG(mapping != nullptr);
DXASSERT_NOMSG(pResult != nullptr);
MSFileSystemHandle *fsHandle =
reinterpret_cast<MSFileSystemHandle *>(mapping);
DXASSERT(fsHandle->kind ==
MSFileSystemHandle::MSFileSystemHandleKind_FileMappingHandle,
"otherwise caller is passing wrong handle to API");
*pResult = fsHandle->storage.p;
DXASSERT(*pResult != nullptr,
"otherwise it should not be requested through GetHandleMapping");
(*pResult)->AddRef();
}
void MSFileSystemForIface::GetHandleStorage(HANDLE fileHandle,
IUnknown **pResult) throw() {
DXASSERT_NOMSG(fileHandle != nullptr);
DXASSERT_NOMSG(pResult != nullptr);
MSFileSystemHandle *fsHandle =
reinterpret_cast<MSFileSystemHandle *>(fileHandle);
DXASSERT(fsHandle->kind ==
MSFileSystemHandle::MSFileSystemHandleKind_FileHandle,
"otherwise caller is passing wrong handle to API");
*pResult = fsHandle->storage.p;
DXASSERT(*pResult != nullptr,
"otherwise it should not be requested through GetHandleStorage");
(*pResult)->AddRef();
}
void MSFileSystemForIface::GetHandleStream(HANDLE fileHandle,
IStream **pResult) throw() {
DXASSERT_NOMSG(fileHandle != nullptr);
DXASSERT_NOMSG(pResult != nullptr);
MSFileSystemHandle *fsHandle =
reinterpret_cast<MSFileSystemHandle *>(fileHandle);
DXASSERT(fsHandle->kind ==
MSFileSystemHandle::MSFileSystemHandleKind_FileHandle,
"otherwise caller is passing wrong handle to API");
*pResult = fsHandle->stream.p;
DXASSERT(*pResult != nullptr,
"otherwise it should not be requested through GetHandleStream");
(*pResult)->AddRef();
}
HANDLE MSFileSystemForIface::FindFirstFileW(
LPCWSTR lpFileName, LPWIN32_FIND_DATAW lpFindFileData) throw() {
HRESULT hr = S_OK;
CComPtr<IEnumSTATSTG> enumStatStg;
HANDLE resultValue = INVALID_HANDLE_VALUE;
STATSTG elt;
ULONG fetched;
ZeroMemory(&elt, sizeof(elt));
ZeroMemory(lpFindFileData, sizeof(*lpFindFileData));
fetched = 0;
IFC(m_system->EnumFiles(lpFileName, &enumStatStg));
IFC(enumStatStg->Next(1, &elt, &fetched));
if (fetched == 0) {
IFC(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
} else {
IFC(CopyStatStg(&elt, lpFindFileData));
IFC(AddFindHandle(enumStatStg, &resultValue));
}
Cleanup:
ClearStatStg(&elt);
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return INVALID_HANDLE_VALUE;
}
DXASSERT(resultValue != INVALID_HANDLE_VALUE,
"otherwise AddFindHandle failed to return a valid handle");
return resultValue;
}
BOOL MSFileSystemForIface::FindNextFileW(
HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) throw() {
HRESULT hr = S_OK;
CComPtr<IEnumSTATSTG> enumStatStg;
STATSTG elt;
ULONG fetched;
ZeroMemory(&elt, sizeof(elt));
ZeroMemory(lpFindFileData, sizeof(*lpFindFileData));
fetched = 0;
GetFindHandle(hFindFile, &enumStatStg);
IFC(enumStatStg->Next(1, &elt, &fetched));
if (fetched == 0) {
IFC(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
} else {
IFC(CopyStatStg(&elt, lpFindFileData));
}
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return FALSE;
}
return TRUE;
}
void MSFileSystemForIface::FindClose(HANDLE findHandle) throw() {
CloseInternalHandle(findHandle);
}
HANDLE MSFileSystemForIface::CreateFileW(LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes) throw() {
HRESULT hr = S_OK;
CComPtr<IUnknown> storage;
CComPtr<IStream> stream;
HANDLE resultHandle = INVALID_HANDLE_VALUE;
IFC(m_system->OpenStorage(lpFileName, dwDesiredAccess, dwShareMode,
dwCreationDisposition, dwFlagsAndAttributes,
&storage));
IFC(storage.QueryInterface(&stream));
IFC(AddFileHandle(storage, stream, &resultHandle));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return INVALID_HANDLE_VALUE;
}
return resultHandle;
}
BOOL MSFileSystemForIface::SetFileTime(
HANDLE hFile, const FILETIME *lpCreationTime,
const FILETIME *lpLastAccessTime, const FILETIME *lpLastWriteTime) throw() {
HRESULT hr = S_OK;
CComPtr<IUnknown> storage;
GetHandleStorage(hFile, &storage);
IFC(m_system->SetStorageTime(storage, lpCreationTime, lpLastAccessTime,
lpLastWriteTime));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return FALSE;
}
return TRUE;
}
BOOL MSFileSystemForIface::GetFileInformationByHandle(
HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation) throw() {
HRESULT hr = S_OK;
CComPtr<IUnknown> storage;
GetHandleStorage(hFile, &storage);
IFC(m_system->GetFileInformationForStorage(storage, lpFileInformation));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return FALSE;
}
return TRUE;
}
DWORD MSFileSystemForIface::GetFileType(HANDLE hFile) throw() {
HRESULT hr = S_OK;
CComPtr<IUnknown> storage;
DWORD fileType;
GetHandleStorage(hFile, &storage);
IFC(m_system->GetFileTypeForStorage(storage, &fileType));
if (fileType == FILE_TYPE_UNKNOWN) {
SetLastError(NO_ERROR);
}
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
fileType = FILE_TYPE_UNKNOWN;
}
return fileType;
}
BOOL MSFileSystemForIface::CreateHardLinkW(LPCWSTR lpFileName,
LPCWSTR lpExistingFileName) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
BOOL MSFileSystemForIface::MoveFileExW(LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
DWORD dwFlags) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
DWORD MSFileSystemForIface::GetFileAttributesW(LPCWSTR lpFileName) throw() {
HRESULT hr = S_OK;
DWORD attributes;
IFC(m_system->GetFileAttributesForStorage(lpFileName, &attributes));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
attributes = INVALID_FILE_ATTRIBUTES;
}
return attributes;
}
BOOL MSFileSystemForIface::CloseHandle(HANDLE hObject) throw() {
this->CloseInternalHandle(hObject);
return TRUE;
}
BOOL MSFileSystemForIface::DeleteFileW(LPCWSTR lpFileName) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
BOOL MSFileSystemForIface::RemoveDirectoryW(LPCWSTR lpFileName) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
BOOL MSFileSystemForIface::CreateDirectoryW(LPCWSTR lpPathName) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
DWORD MSFileSystemForIface::GetCurrentDirectoryW(DWORD nBufferLength,
LPWSTR lpBuffer) throw() {
DWORD written = 0;
HRESULT hr = S_OK;
IFC(m_system->GetCurrentDirectoryForStorage(nBufferLength, lpBuffer,
&written));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return 0;
}
return written;
}
DWORD MSFileSystemForIface::GetMainModuleFileNameW(LPWSTR lpFilename,
DWORD nSize) throw() {
DWORD written = 0;
HRESULT hr = S_OK;
IFC(m_system->GetMainModuleFileNameW(nSize, lpFilename, &written));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return 0;
}
return written;
}
DWORD MSFileSystemForIface::GetTempPathW(DWORD nBufferLength,
LPWSTR lpBuffer) throw() {
DWORD written = 0;
HRESULT hr = S_OK;
IFC(m_system->GetTempStoragePath(nBufferLength, lpBuffer, &written));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return 0;
}
return written;
}
BOOLEAN MSFileSystemForIface::CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName,
LPCWSTR lpTargetFileName,
DWORD dwFlags) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
bool MSFileSystemForIface::SupportsCreateSymbolicLink() throw() {
return false;
}
BOOL MSFileSystemForIface::ReadFile(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead) throw() {
HRESULT hr = S_OK;
CComPtr<IStream> stream;
GetHandleStream(hFile, &stream);
ULONG cbRead;
IFC(stream->Read(lpBuffer, nNumberOfBytesToRead, &cbRead));
if (lpNumberOfBytesRead != nullptr) {
*lpNumberOfBytesRead = cbRead;
}
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return FALSE;
}
return TRUE;
}
HANDLE
MSFileSystemForIface::CreateFileMappingW(HANDLE hFile, DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow) throw() {
HRESULT hr = S_OK;
HANDLE result = INVALID_HANDLE_VALUE;
CComPtr<IUnknown> storage;
CComPtr<IUnknown> mapping;
GetHandleStorage(hFile, &storage);
IFC(m_system->CreateStorageMapping(storage, flProtect, dwMaximumSizeHigh,
dwMaximumSizeLow, &mapping));
IFC(AddMappingHandle(mapping, &result));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return INVALID_HANDLE_VALUE;
}
return result;
}
LPVOID MSFileSystemForIface::MapViewOfFile(
HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) throw() {
HRESULT hr = S_OK;
CComPtr<IUnknown> mapping;
CComPtr<ID3D10Blob> blob;
GetHandleMapping(hFileMappingObject, &mapping);
IFC(m_system->MapViewOfFile(mapping, dwDesiredAccess, dwFileOffsetHigh,
dwFileOffsetLow, dwNumberOfBytesToMap, &blob));
IFC(AddMappingView(blob));
Cleanup:
if (FAILED(hr)) {
SetLastError(WIN32_FROM_HRESULT(hr));
return INVALID_HANDLE_VALUE;
}
return blob->GetBufferPointer();
}
BOOL MSFileSystemForIface::UnmapViewOfFile(LPCVOID lpBaseAddress) throw() {
RemoveMappingView(lpBaseAddress);
return TRUE;
}
bool MSFileSystemForIface::FileDescriptorIsDisplayed(int fd) throw() {
return false;
}
unsigned MSFileSystemForIface::GetColumnCount(DWORD nStdHandle) throw() {
return 0;
}
unsigned MSFileSystemForIface::GetConsoleOutputTextAttributes() throw() {
return 0;
}
void MSFileSystemForIface::SetConsoleOutputTextAttributes(
unsigned attributes) throw() {
return;
}
void MSFileSystemForIface::ResetConsoleOutputTextAttributes() throw() {}
int MSFileSystemForIface::open_osfhandle(intptr_t osfhandle,
int flags) throw() {
return GetHandleFD((HANDLE)osfhandle);
}
HRESULT MSFileSystemForIface::EnsureFDAvailable(int fd) {
MSFileSystemHandle *ptr;
switch (fd) {
case 0:
ptr = &m_knownHandle0;
break;
case 1:
ptr = &m_knownHandle1;
break;
case 2:
ptr = &m_knownHandle2;
break;
default:
return S_OK;
}
HRESULT hr = S_OK;
if (ptr->storage == nullptr) {
CComPtr<IUnknown> storage;
CComPtr<IStream> stream;
IFC(m_system->OpenStdStorage(fd, &storage));
IFC(storage.QueryInterface(&stream));
ptr->storage = storage;
ptr->stream = stream;
}
DXASSERT(ptr->storage != nullptr,
"otherwise we should have failed to initialize");
DXASSERT(ptr->stream != nullptr,
"otherwise we should have failed to initialize - input/output/error "
"should support streams");
Cleanup:
return hr;
}
HANDLE MSFileSystemForIface::GetHandleForFD(int fd) throw() {
MSFileSystemHandle *ptr;
switch (fd) {
case 0:
ptr = &m_knownHandle0;
break;
case 1:
ptr = &m_knownHandle1;
break;
case 2:
ptr = &m_knownHandle2;
break;
default:
ptr = (MSFileSystemHandle *)(uintptr_t)fd;
break;
}
return ptr->GetHandle();
}
intptr_t MSFileSystemForIface::get_osfhandle(int fd) throw() {
if (FAILED(EnsureFDAvailable(fd))) {
errno = EBADF;
return -1;
}
return (intptr_t)GetHandleForFD(fd);
}
int MSFileSystemForIface::close(int fd) throw() {
HANDLE h = GetHandleForFD(fd);
this->CloseInternalHandle(h);
return 0;
}
long MSFileSystemForIface::lseek(int fd, long offset, int origin) throw() {
HRESULT hr = S_OK;
CComPtr<IStream> stream;
LARGE_INTEGER li;
ULARGE_INTEGER uli;
if (FAILED(EnsureFDAvailable(fd))) {
errno = EBADF;
return -1;
}
GetHandleStream(GetHandleForFD(fd), &stream);
li.HighPart = 0;
li.LowPart = offset;
IFC(stream->Seek(li, origin, &uli));
Cleanup:
if (FAILED(hr)) {
errno = EINVAL;
return -1;
}
if (uli.HighPart > 0) {
errno = EOVERFLOW;
return -1;
}
return uli.LowPart;
}
int MSFileSystemForIface::setmode(int fd, int mode) throw() { return 0; }
errno_t MSFileSystemForIface::resize_file(LPCWSTR path, uint64_t size) throw() {
return EBADF;
}
int MSFileSystemForIface::Read(int fd, void *buffer,
unsigned int count) throw() {
HRESULT hr = S_OK;
CComPtr<IStream> stream;
ULONG cbRead = 0;
if (FAILED(EnsureFDAvailable(fd))) {
errno = EBADF;
return -1;
}
GetHandleStream(GetHandleForFD(fd), &stream);
IFC(stream->Read(buffer, count, &cbRead));
Cleanup:
if (FAILED(hr)) {
errno = EINVAL;
return -1;
}
return (int)cbRead;
}
int MSFileSystemForIface::Write(int fd, const void *buffer,
unsigned int count) throw() {
HRESULT hr = S_OK;
CComPtr<IStream> stream;
ULONG cbWritten = 0;
if (FAILED(EnsureFDAvailable(fd))) {
errno = EBADF;
return -1;
}
GetHandleStream(GetHandleForFD(fd), &stream);
IFC(stream->Write(buffer, count, &cbWritten));
Cleanup:
if (FAILED(hr)) {
errno = EINVAL;
return -1;
}
return (int)cbWritten;
}
#ifndef _WIN32
int MSFileSystemForIface::Open(const char *lpFileName, int flags,
mode_t mode) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
int MSFileSystemForIface::Stat(const char *lpFileName,
struct stat *Status) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
int MSFileSystemForIface::Fstat(int FD, struct stat *Status) throw() {
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
#endif
} // end namespace fs
} // end namespace sys
} // end namespace llvm
///////////////////////////////////////////////////////////////////////////////////////////////////
// Blocked MSFileSystem implementation.
#ifndef NDEBUG
static void MSFileSystemBlockedCalled() { DebugBreak(); }
#else
static void MSFileSystemBlockedCalled() {}
#endif
static BOOL MSFileSystemBlockedErrWin32() {
MSFileSystemBlockedCalled();
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return FALSE;
}
static HANDLE MSFileSystemBlockedHandle() {
MSFileSystemBlockedCalled();
SetLastError(ERROR_FUNCTION_NOT_CALLED);
return INVALID_HANDLE_VALUE;
}
static int MSFileSystemBlockedErrno() {
MSFileSystemBlockedCalled();
errno = EBADF;
return -1;
}
static int MSFileSystemBlockedErrnoT() {
MSFileSystemBlockedCalled();
return EBADF;
}
namespace llvm {
namespace sys {
namespace fs {
class MSFileSystemBlocked : public MSFileSystem {
private:
public:
MSFileSystemBlocked();
virtual BOOL FindNextFileW(HANDLE, LPWIN32_FIND_DATAW) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual HANDLE
FindFirstFileW(LPCWSTR lpFileName,
LPWIN32_FIND_DATAW lpFindFileData) throw() override {
return MSFileSystemBlockedHandle();
}
virtual void FindClose(HANDLE findHandle) throw() override {
MSFileSystemBlockedCalled();
}
virtual HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes) throw() override {
return MSFileSystemBlockedHandle();
}
virtual BOOL SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime,
const FILETIME *lpLastAccessTime,
const FILETIME *lpLastWriteTime) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual BOOL GetFileInformationByHandle(
HANDLE hFile,
LPBY_HANDLE_FILE_INFORMATION lpFileInformation) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual DWORD GetFileType(HANDLE hFile) throw() override {
MSFileSystemBlockedErrWin32();
return FILE_TYPE_UNKNOWN;
}
virtual BOOL CreateHardLinkW(LPCWSTR lpFileName,
LPCWSTR lpExistingFileName) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual BOOL MoveFileExW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName,
DWORD dwFlags) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual DWORD GetFileAttributesW(LPCWSTR lpFileName) throw() override {
MSFileSystemBlockedErrWin32();
return 0;
}
virtual BOOL CloseHandle(HANDLE hObject) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual BOOL DeleteFileW(LPCWSTR lpFileName) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual BOOL RemoveDirectoryW(LPCWSTR lpFileName) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual BOOL CreateDirectoryW(LPCWSTR lpPathName) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual DWORD GetCurrentDirectoryW(DWORD nBufferLength,
LPWSTR lpBuffer) throw() override;
virtual DWORD GetMainModuleFileNameW(LPWSTR lpFilename,
DWORD nSize) throw() override;
virtual DWORD GetTempPathW(DWORD nBufferLength,
LPWSTR lpBuffer) throw() override;
virtual BOOLEAN CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName,
LPCWSTR lpTargetFileName,
DWORD dwFlags) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual bool SupportsCreateSymbolicLink() throw() override {
MSFileSystemBlockedErrWin32();
return false;
}
virtual BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead) throw() override {
return MSFileSystemBlockedErrWin32();
}
virtual HANDLE CreateFileMappingW(HANDLE hFile, DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow) throw() override {
return MSFileSystemBlockedHandle();
}
virtual LPVOID MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess,
DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow,
SIZE_T dwNumberOfBytesToMap) throw() override {
MSFileSystemBlockedErrWin32();
return nullptr;
}
virtual BOOL UnmapViewOfFile(LPCVOID lpBaseAddress) throw() override {
return MSFileSystemBlockedErrWin32();
}
// Console APIs.
virtual bool FileDescriptorIsDisplayed(int fd) throw() override {
MSFileSystemBlockedCalled();
return false;
}
virtual unsigned GetColumnCount(DWORD nStdHandle) throw() override {
MSFileSystemBlockedCalled();
return 80;
}
virtual unsigned GetConsoleOutputTextAttributes() throw() override {
MSFileSystemBlockedCalled();
return 0;
}
virtual void
SetConsoleOutputTextAttributes(unsigned attributes) throw() override {
MSFileSystemBlockedCalled();
}
virtual void ResetConsoleOutputTextAttributes() throw() override {
MSFileSystemBlockedCalled();
}
// CRT APIs.
virtual int open_osfhandle(intptr_t osfhandle, int flags) throw() override {
return MSFileSystemBlockedErrno();
}
virtual intptr_t get_osfhandle(int fd) throw() override {
MSFileSystemBlockedErrno();
return 0;
}
virtual int close(int fd) throw() override {
return MSFileSystemBlockedErrno();
}
virtual long lseek(int fd, long offset, int origin) throw() override {
return MSFileSystemBlockedErrno();
}
virtual int setmode(int fd, int mode) throw() override {
return MSFileSystemBlockedErrno();
}
virtual errno_t resize_file(LPCWSTR path, uint64_t size) throw() override {
return MSFileSystemBlockedErrnoT();
}
virtual int Read(int fd, void *buffer, unsigned int count) throw() override {
return MSFileSystemBlockedErrno();
}
virtual int Write(int fd, const void *buffer,
unsigned int count) throw() override {
return MSFileSystemBlockedErrno();
}
// Unix interface
#ifndef _WIN32
virtual int Open(const char *lpFileName, int flags,
mode_t mode) throw() override {
return MSFileSystemBlockedErrno();
}
virtual int Stat(const char *lpFileName,
struct stat *Status) throw() override {
return MSFileSystemBlockedErrno();
}
virtual int Fstat(int FD, struct stat *Status) throw() override {
return MSFileSystemBlockedErrno();
}
#endif
};
MSFileSystemBlocked::MSFileSystemBlocked() {}
DWORD MSFileSystemBlocked::GetCurrentDirectoryW(DWORD nBufferLength,
LPWSTR lpBuffer) throw() {
if (nBufferLength > 1) {
lpBuffer[0] = L'.';
lpBuffer[1] = L'\0';
}
return 1;
}
DWORD MSFileSystemBlocked::GetMainModuleFileNameW(LPWSTR lpFilename,
DWORD nSize) throw() {
SetLastError(NO_ERROR);
return 0;
}
DWORD MSFileSystemBlocked::GetTempPathW(DWORD nBufferLength,
LPWSTR lpBuffer) throw() {
if (nBufferLength > 1) {
lpBuffer[0] = L'.';
lpBuffer[1] = L'\0';
}
return 1;
}
} // end namespace fs
} // end namespace sys
} // end namespace llvm
///////////////////////////////////////////////////////////////////////////////////////////////////
// Externally visible functions.
HRESULT
CreateMSFileSystemForIface(IUnknown *pService,
::llvm::sys::fs::MSFileSystem **pResult) throw() {
DXASSERT_NOMSG(pService != nullptr);
DXASSERT_NOMSG(pResult != nullptr);
CComPtr<IDxcSystemAccess> systemAccess;
HRESULT hr = pService->QueryInterface(__uuidof(IDxcSystemAccess),
(void **)&systemAccess);
if (FAILED(hr))
return hr;
*pResult =
new (std::nothrow)::llvm::sys::fs::MSFileSystemForIface(systemAccess);
return (*pResult != nullptr) ? S_OK : E_OUTOFMEMORY;
}
HRESULT
CreateMSFileSystemBlocked(::llvm::sys::fs::MSFileSystem **pResult) throw() {
DXASSERT_NOMSG(pResult != nullptr);
*pResult = new (std::nothrow)::llvm::sys::fs::MSFileSystemBlocked();
return (*pResult != nullptr) ? S_OK : E_OUTOFMEMORY;
}
#endif // _WIN32