2023-11-30 09:18:10 -06:00

903 lines
38 KiB
C++

/**
* @file winfsp/winfsp.hpp
* WinFsp C++ Layer.
*
* @copyright 2015-2022 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this software
* in accordance with the commercial license agreement provided in
* conjunction with the software. The terms and conditions of any such
* commercial license agreement shall govern, supersede, and render
* ineffective any application of the GPLv3 license to this software,
* notwithstanding of any reference thereto in the software or
* associated repository.
*/
#ifndef WINFSP_WINFSP_HPP_INCLUDED
#define WINFSP_WINFSP_HPP_INCLUDED
#ifndef __cplusplus
#error this header requires a C++ compiler
#endif
#include <winfsp/winfsp.h>
#define FSP_CPP_EXCEPTION_GUARD(...) \
try { \
__VA_ARGS__ \
} catch (...) { \
return self->ExceptionHandler(); \
}
#define FSP_CPP_EXCEPTION_GUARD_VOID(...) \
try { \
__VA_ARGS__ \
} catch (...) { \
self->ExceptionHandler(); \
return; \
}
namespace Fsp {
inline NTSTATUS Initialize() {
static NTSTATUS LoadResult = FspLoad(0);
return LoadResult;
}
class FileSystemBase {
public:
typedef FSP_FSCTL_VOLUME_INFO VolumeInfo;
typedef FSP_FSCTL_FILE_INFO FileInfo;
typedef FSP_FSCTL_OPEN_FILE_INFO OpenFileInfo;
typedef FSP_FSCTL_DIR_INFO DirInfo;
typedef FSP_FSCTL_STREAM_INFO StreamInfo;
enum CleanupFlags {
CleanupDelete = FspCleanupDelete,
CleanupSetAllocationSize = FspCleanupSetAllocationSize,
CleanupSetArchiveBit = FspCleanupSetArchiveBit,
CleanupSetLastAccessTime = FspCleanupSetLastAccessTime,
CleanupSetLastWriteTime = FspCleanupSetLastWriteTime,
CleanupSetChangeTime = FspCleanupSetChangeTime,
};
public:
FileSystemBase() {}
virtual ~FileSystemBase() {}
/* operations */
virtual NTSTATUS ExceptionHandler() { return STATUS_UNEXPECTED_IO_ERROR; }
virtual NTSTATUS Init(PVOID Host) { return STATUS_SUCCESS; }
virtual NTSTATUS Mounted(PVOID Host) { return STATUS_SUCCESS; }
virtual VOID Unmounted(PVOID Host) {}
virtual NTSTATUS GetVolumeInfo(VolumeInfo *VolumeInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS SetVolumeLabel_(PWSTR VolumeLabel, VolumeInfo *VolumeInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS
GetSecurityByName(PWSTR FileName,
PUINT32 PFileAttributes /* or ReparsePointIndex */,
PSECURITY_DESCRIPTOR SecurityDescriptor,
SIZE_T *PSecurityDescriptorSize) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS Create(PWSTR FileName, UINT32 CreateOptions,
UINT32 GrantedAccess, UINT32 FileAttributes,
PSECURITY_DESCRIPTOR SecurityDescriptor,
UINT64 AllocationSize, PVOID *PFileNode,
PVOID *PFileDesc, OpenFileInfo *OpenFileInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS Open(PWSTR FileName, UINT32 CreateOptions,
UINT32 GrantedAccess, PVOID *PFileNode,
PVOID *PFileDesc, OpenFileInfo *OpenFileInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS Overwrite(PVOID FileNode, PVOID FileDesc,
UINT32 FileAttributes,
BOOLEAN ReplaceFileAttributes,
UINT64 AllocationSize, FileInfo *FileInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual VOID Cleanup(PVOID FileNode, PVOID FileDesc, PWSTR FileName,
ULONG Flags) {}
virtual VOID Close(PVOID FileNode, PVOID FileDesc) {}
virtual NTSTATUS Read(PVOID FileNode, PVOID FileDesc, PVOID Buffer,
UINT64 Offset, ULONG Length, PULONG PBytesTransferred) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS Write(PVOID FileNode, PVOID FileDesc, PVOID Buffer,
UINT64 Offset, ULONG Length, BOOLEAN WriteToEndOfFile,
BOOLEAN ConstrainedIo, PULONG PBytesTransferred,
FileInfo *FileInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS Flush(PVOID FileNode, PVOID FileDesc, FileInfo *FileInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS GetFileInfo(PVOID FileNode, PVOID FileDesc,
FileInfo *FileInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS SetBasicInfo(PVOID FileNode, PVOID FileDesc,
UINT32 FileAttributes, UINT64 CreationTime,
UINT64 LastAccessTime, UINT64 LastWriteTime,
UINT64 ChangeTime, FileInfo *FileInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS SetFileSize(PVOID FileNode, PVOID FileDesc, UINT64 NewSize,
BOOLEAN SetAllocationSize, FileInfo *FileInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS CanDelete(PVOID FileNode, PVOID FileDesc, PWSTR FileName) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS Rename(PVOID FileNode, PVOID FileDesc, PWSTR FileName,
PWSTR NewFileName, BOOLEAN ReplaceIfExists) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS GetSecurity(PVOID FileNode, PVOID FileDesc,
PSECURITY_DESCRIPTOR SecurityDescriptor,
SIZE_T *PSecurityDescriptorSize) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS SetSecurity(PVOID FileNode, PVOID FileDesc,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ModificationDescriptor) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS ReadDirectory(PVOID FileNode, PVOID FileDesc, PWSTR Pattern,
PWSTR Marker, PVOID Buffer, ULONG Length,
PULONG PBytesTransferred) {
return SeekableReadDirectory(FileNode, FileDesc, Pattern, Marker, Buffer,
Length, PBytesTransferred);
}
virtual NTSTATUS ReadDirectoryEntry(PVOID FileNode, PVOID FileDesc,
PWSTR Pattern, PWSTR Marker,
PVOID *PContext, DirInfo *DirInfo) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS ResolveReparsePoints(PWSTR FileName,
UINT32 ReparsePointIndex,
BOOLEAN ResolveLastPathComponent,
PIO_STATUS_BLOCK PIoStatus,
PVOID Buffer, PSIZE_T PSize) {
return FspFileSystemResolveReparsePoints(
0, GetReparsePointByName, this, FileName, ReparsePointIndex,
ResolveLastPathComponent, PIoStatus, Buffer, PSize);
}
virtual NTSTATUS GetReparsePointByName(PWSTR FileName, BOOLEAN IsDirectory,
PVOID Buffer, PSIZE_T PSize) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS GetReparsePoint(PVOID FileNode, PVOID FileDesc,
PWSTR FileName, PVOID Buffer,
PSIZE_T PSize) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS SetReparsePoint(PVOID FileNode, PVOID FileDesc,
PWSTR FileName, PVOID Buffer, SIZE_T Size) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS DeleteReparsePoint(PVOID FileNode, PVOID FileDesc,
PWSTR FileName, PVOID Buffer,
SIZE_T Size) {
return STATUS_INVALID_DEVICE_REQUEST;
}
virtual NTSTATUS GetStreamInfo(PVOID FileNode, PVOID FileDesc, PVOID Buffer,
ULONG Length, PULONG PBytesTransferred) {
return STATUS_INVALID_DEVICE_REQUEST;
}
/* helpers */
static NTSTATUS NtStatusFromWin32(DWORD Error) {
return FspNtStatusFromWin32(Error);
}
static DWORD Win32FromNtStatus(NTSTATUS Status) {
return FspWin32FromNtStatus(Status);
}
static VOID DeleteDirectoryBuffer(PVOID *PDirBuffer) {
FspFileSystemDeleteDirectoryBuffer(PDirBuffer);
}
NTSTATUS SeekableReadDirectory(PVOID FileNode, PVOID FileDesc, PWSTR Pattern,
PWSTR Marker, PVOID Buffer, ULONG Length,
PULONG PBytesTransferred) {
PVOID Context = 0;
union {
UINT8 B[FIELD_OFFSET(FileSystemBase::DirInfo, FileNameBuf) +
MAX_PATH * sizeof(WCHAR)];
FileSystemBase::DirInfo D;
} DirInfoBuf;
FileSystemBase::DirInfo *DirInfo = &DirInfoBuf.D;
NTSTATUS Result = STATUS_SUCCESS;
*PBytesTransferred = 0;
for (;;) {
Result = ReadDirectoryEntry(FileNode, FileDesc, Pattern, Marker, &Context,
DirInfo);
if (STATUS_NO_MORE_FILES == Result) {
Result = STATUS_SUCCESS;
break;
}
if (!NT_SUCCESS(Result))
break;
if (!FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred))
break;
}
if (!NT_SUCCESS(Result))
return Result;
return STATUS_SUCCESS;
}
NTSTATUS BufferedReadDirectory(PVOID *PDirBuffer, PVOID FileNode,
PVOID FileDesc, PWSTR Pattern, PWSTR Marker,
PVOID Buffer, ULONG Length,
PULONG PBytesTransferred) {
PVOID Context = 0;
union {
UINT8 B[FIELD_OFFSET(FileSystemBase::DirInfo, FileNameBuf) +
MAX_PATH * sizeof(WCHAR)];
FileSystemBase::DirInfo D;
} DirInfoBuf;
FileSystemBase::DirInfo *DirInfo = &DirInfoBuf.D;
NTSTATUS Result = STATUS_SUCCESS;
*PBytesTransferred = 0;
if (FspFileSystemAcquireDirectoryBuffer(PDirBuffer, 0 == Marker, &Result)) {
try {
for (;;) {
Result = ReadDirectoryEntry(FileNode, FileDesc, Pattern, Marker,
&Context, DirInfo);
if (STATUS_NO_MORE_FILES == Result) {
Result = STATUS_SUCCESS;
break;
}
if (!NT_SUCCESS(Result))
break;
if (!FspFileSystemFillDirectoryBuffer(PDirBuffer, DirInfo, &Result))
break;
}
} catch (...) {
FspFileSystemReleaseDirectoryBuffer(PDirBuffer);
throw;
}
FspFileSystemReleaseDirectoryBuffer(PDirBuffer);
}
if (!NT_SUCCESS(Result))
return Result;
FspFileSystemReadDirectoryBuffer(PDirBuffer, Marker, Buffer, Length,
PBytesTransferred);
return STATUS_SUCCESS;
}
BOOLEAN FindReparsePoint(PWSTR FileName, PUINT32 PReparsePointIndex) {
return FspFileSystemFindReparsePoint(0, GetReparsePointByName, this,
FileName, PReparsePointIndex);
}
static NTSTATUS CanReplaceReparsePoint(PVOID CurrentReparseData,
SIZE_T CurrentReparseDataSize,
PVOID ReplaceReparseData,
SIZE_T ReplaceReparseDataSize) {
return FspFileSystemCanReplaceReparsePoint(
CurrentReparseData, CurrentReparseDataSize, ReplaceReparseData,
ReplaceReparseDataSize);
}
static BOOLEAN AddStreamInfo(StreamInfo *StreamInfo, PVOID Buffer,
ULONG Length, PULONG PBytesTransferred) {
return FspFileSystemAddStreamInfo(StreamInfo, Buffer, Length,
PBytesTransferred);
}
private:
static NTSTATUS GetReparsePointByName(FSP_FILE_SYSTEM *FileSystem,
PVOID Context, PWSTR FileName,
BOOLEAN IsDirectory, PVOID Buffer,
PSIZE_T PSize) {
FileSystemBase *self = (FileSystemBase *)Context;
FSP_CPP_EXCEPTION_GUARD(return self->GetReparsePointByName(
FileName, IsDirectory, Buffer, PSize);)
}
private:
/* disallow copy and assignment */
FileSystemBase(const FileSystemBase &);
FileSystemBase &operator=(const FileSystemBase &);
};
class FileSystemHost {
public:
/* ctor/dtor */
FileSystemHost(FileSystemBase &FileSystem)
: _VolumeParams(), _FileSystemPtr(0), _FileSystem(&FileSystem) {
Initialize();
_VolumeParams.UmFileContextIsFullContext = 1;
}
virtual ~FileSystemHost() {
if (0 != _FileSystemPtr)
FspFileSystemDelete(_FileSystemPtr);
}
/* properties */
UINT16 SectorSize() { return _VolumeParams.SectorSize; }
VOID SetSectorSize(UINT16 SectorSize) {
_VolumeParams.SectorSize = SectorSize;
}
UINT16 SectorsPerAllocationUnit() {
return _VolumeParams.SectorsPerAllocationUnit;
}
VOID SetSectorsPerAllocationUnit(UINT16 SectorsPerAllocationUnit) {
_VolumeParams.SectorsPerAllocationUnit = SectorsPerAllocationUnit;
}
UINT16 MaxComponentLength() { return _VolumeParams.MaxComponentLength; }
VOID SetMaxComponentLength(UINT16 MaxComponentLength) {
_VolumeParams.MaxComponentLength = MaxComponentLength;
}
UINT64 VolumeCreationTime() { return _VolumeParams.VolumeCreationTime; }
VOID SetVolumeCreationTime(UINT64 VolumeCreationTime) {
_VolumeParams.VolumeCreationTime = VolumeCreationTime;
}
UINT32 VolumeSerialNumber() { return _VolumeParams.VolumeSerialNumber; }
VOID SetVolumeSerialNumber(UINT32 VolumeSerialNumber) {
_VolumeParams.VolumeSerialNumber = VolumeSerialNumber;
}
UINT32 FileInfoTimeout() { return _VolumeParams.FileInfoTimeout; }
VOID SetFileInfoTimeout(UINT32 FileInfoTimeout) {
_VolumeParams.FileInfoTimeout = FileInfoTimeout;
}
BOOLEAN CaseSensitiveSearch() { return _VolumeParams.CaseSensitiveSearch; }
VOID SetCaseSensitiveSearch(BOOLEAN CaseSensitiveSearch) {
_VolumeParams.CaseSensitiveSearch = !!CaseSensitiveSearch;
}
BOOLEAN CasePreservedNames() { return _VolumeParams.CasePreservedNames; }
VOID SetCasePreservedNames(BOOLEAN CasePreservedNames) {
_VolumeParams.CasePreservedNames = !!CasePreservedNames;
}
BOOLEAN UnicodeOnDisk() { return _VolumeParams.UnicodeOnDisk; }
VOID SetUnicodeOnDisk(BOOLEAN UnicodeOnDisk) {
_VolumeParams.UnicodeOnDisk = !!UnicodeOnDisk;
}
BOOLEAN PersistentAcls() { return _VolumeParams.PersistentAcls; }
VOID SetPersistentAcls(BOOLEAN PersistentAcls) {
_VolumeParams.PersistentAcls = !!PersistentAcls;
}
BOOLEAN ReparsePoints() { return _VolumeParams.ReparsePoints; }
VOID SetReparsePoints(BOOLEAN ReparsePoints) {
_VolumeParams.ReparsePoints = !!ReparsePoints;
}
BOOLEAN ReparsePointsAccessCheck() {
return _VolumeParams.ReparsePointsAccessCheck;
}
VOID SetReparsePointsAccessCheck(BOOLEAN ReparsePointsAccessCheck) {
_VolumeParams.ReparsePointsAccessCheck = !!ReparsePointsAccessCheck;
}
BOOLEAN NamedStreams() { return _VolumeParams.NamedStreams; }
VOID SetNamedStreams(BOOLEAN NamedStreams) {
_VolumeParams.NamedStreams = !!NamedStreams;
}
BOOLEAN PostCleanupWhenModifiedOnly() {
return _VolumeParams.PostCleanupWhenModifiedOnly;
}
VOID SetPostCleanupWhenModifiedOnly(BOOLEAN PostCleanupWhenModifiedOnly) {
_VolumeParams.PostCleanupWhenModifiedOnly = !!PostCleanupWhenModifiedOnly;
}
BOOLEAN PassQueryDirectoryPattern() {
return _VolumeParams.PassQueryDirectoryPattern;
}
VOID SetPassQueryDirectoryPattern(BOOLEAN PassQueryDirectoryPattern) {
_VolumeParams.PassQueryDirectoryPattern = !!PassQueryDirectoryPattern;
}
BOOLEAN FlushAndPurgeOnCleanup() {
return _VolumeParams.FlushAndPurgeOnCleanup;
}
VOID SetFlushAndPurgeOnCleanup(BOOLEAN FlushAndPurgeOnCleanup) {
_VolumeParams.FlushAndPurgeOnCleanup = !!FlushAndPurgeOnCleanup;
}
PWSTR Prefix() { return _VolumeParams.Prefix; }
VOID SetPrefix(PWSTR Prefix) {
int Size = lstrlenW(Prefix) * sizeof(WCHAR);
if (Size > sizeof _VolumeParams.Prefix - sizeof(WCHAR))
Size = sizeof _VolumeParams.Prefix - sizeof(WCHAR);
RtlCopyMemory(_VolumeParams.Prefix, Prefix, Size);
_VolumeParams.Prefix[Size / sizeof(WCHAR)] = L'\0';
}
PWSTR FileSystemName() { return _VolumeParams.FileSystemName; }
VOID SetFileSystemName(PWSTR FileSystemName) {
int Size = lstrlenW(FileSystemName) * sizeof(WCHAR);
if (Size > sizeof _VolumeParams.FileSystemName - sizeof(WCHAR))
Size = sizeof _VolumeParams.FileSystemName - sizeof(WCHAR);
RtlCopyMemory(_VolumeParams.FileSystemName, FileSystemName, Size);
_VolumeParams.FileSystemName[Size / sizeof(WCHAR)] = L'\0';
}
/* control */
NTSTATUS Preflight(PWSTR MountPoint) {
return FspFileSystemPreflight((PWSTR)(_VolumeParams.Prefix[0]
? L"" FSP_FSCTL_NET_DEVICE_NAME
: L"" FSP_FSCTL_DISK_DEVICE_NAME),
MountPoint);
}
NTSTATUS Mount(PWSTR MountPoint, PSECURITY_DESCRIPTOR SecurityDescriptor = 0,
BOOLEAN Synchronized = FALSE, UINT32 DebugLog = 0) {
NTSTATUS Result;
try {
Result = _FileSystem->Init(this);
} catch (...) {
Result = _FileSystem->ExceptionHandler();
}
if (!NT_SUCCESS(Result))
return Result;
Result = FspFileSystemCreate((PWSTR)(_VolumeParams.Prefix[0]
? L"" FSP_FSCTL_NET_DEVICE_NAME
: L"" FSP_FSCTL_DISK_DEVICE_NAME),
&_VolumeParams, Interface(), &_FileSystemPtr);
if (!NT_SUCCESS(Result))
return Result;
_FileSystemPtr->UserContext = _FileSystem;
FspFileSystemSetOperationGuardStrategy(
_FileSystemPtr, Synchronized
? FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE
: FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE);
FspFileSystemSetDebugLog(_FileSystemPtr, DebugLog);
Result = FspFileSystemSetMountPointEx(_FileSystemPtr, MountPoint,
SecurityDescriptor);
if (NT_SUCCESS(Result)) {
try {
Result = _FileSystem->Mounted(this);
} catch (...) {
Result = _FileSystem->ExceptionHandler();
}
if (NT_SUCCESS(Result)) {
Result = FspFileSystemStartDispatcher(_FileSystemPtr, 0);
if (!NT_SUCCESS(Result))
try {
_FileSystem->Unmounted(this);
} catch (...) {
_FileSystem->ExceptionHandler();
}
}
}
if (!NT_SUCCESS(Result)) {
FspFileSystemDelete(_FileSystemPtr);
_FileSystemPtr = 0;
}
return Result;
}
VOID Unmount() {
FspFileSystemStopDispatcher(_FileSystemPtr);
try {
_FileSystem->Unmounted(this);
} catch (...) {
_FileSystem->ExceptionHandler();
}
_FileSystemPtr->UserContext = 0;
FspFileSystemDelete(_FileSystemPtr);
_FileSystemPtr = 0;
}
PWSTR MountPoint() {
return 0 != _FileSystemPtr ? FspFileSystemMountPoint(_FileSystemPtr) : 0;
}
FSP_FILE_SYSTEM *FileSystemHandle() { return _FileSystemPtr; }
FileSystemBase &FileSystem() { return *_FileSystem; }
static NTSTATUS SetDebugLogFile(PWSTR FileName) {
HANDLE Handle;
if ('-' == FileName[0] && '\0' == FileName[1])
Handle = GetStdHandle(STD_ERROR_HANDLE);
else
Handle = CreateFileW(FileName, FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0);
if (INVALID_HANDLE_VALUE == Handle)
return FspNtStatusFromWin32(GetLastError());
FspDebugLogSetHandle(Handle);
return STATUS_SUCCESS;
}
private:
/* FSP_FILE_SYSTEM_INTERFACE */
static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem0,
FSP_FSCTL_VOLUME_INFO *VolumeInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->GetVolumeInfo(VolumeInfo);)
}
static NTSTATUS SetVolumeLabel_(FSP_FILE_SYSTEM *FileSystem0,
PWSTR VolumeLabel,
FSP_FSCTL_VOLUME_INFO *VolumeInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(
return self->SetVolumeLabel_(VolumeLabel, VolumeInfo);)
}
static NTSTATUS
GetSecurityByName(FSP_FILE_SYSTEM *FileSystem0, PWSTR FileName,
PUINT32 PFileAttributes /* or ReparsePointIndex */,
PSECURITY_DESCRIPTOR SecurityDescriptor,
SIZE_T *PSecurityDescriptorSize) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->GetSecurityByName(
FileName, PFileAttributes, SecurityDescriptor,
PSecurityDescriptorSize);)
}
static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem0, PWSTR FileName,
UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes,
PSECURITY_DESCRIPTOR SecurityDescriptor,
UINT64 AllocationSize, PVOID *FullContext,
FSP_FSCTL_FILE_INFO *FileInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
PVOID FileNode, FileDesc;
NTSTATUS Result;
FSP_CPP_EXCEPTION_GUARD(
Result =
self->Create(FileName, CreateOptions, GrantedAccess, FileAttributes,
SecurityDescriptor, AllocationSize, &FileNode,
&FileDesc, FspFileSystemGetOpenFileInfo(FileInfo));)
((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)->UserContext =
(UINT64)(UINT_PTR)FileNode;
((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)->UserContext2 =
(UINT64)(UINT_PTR)FileDesc;
return Result;
}
static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem0, PWSTR FileName,
UINT32 CreateOptions, UINT32 GrantedAccess,
PVOID *FullContext, FSP_FSCTL_FILE_INFO *FileInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
PVOID FileNode, FileDesc;
NTSTATUS Result;
FSP_CPP_EXCEPTION_GUARD(
Result = self->Open(FileName, CreateOptions, GrantedAccess, &FileNode,
&FileDesc, FspFileSystemGetOpenFileInfo(FileInfo));)
((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)->UserContext =
(UINT64)(UINT_PTR)FileNode;
((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)->UserContext2 =
(UINT64)(UINT_PTR)FileDesc;
return Result;
}
static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
UINT32 FileAttributes,
BOOLEAN ReplaceFileAttributes,
UINT64 AllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->Overwrite(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileAttributes, ReplaceFileAttributes, AllocationSize, FileInfo);)
}
static VOID Cleanup(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
PWSTR FileName, ULONG Flags) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD_VOID(return self->Cleanup(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileName, Flags);)
}
static VOID Close(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD_VOID(return self->Close(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2);)
}
static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
PVOID Buffer, UINT64 Offset, ULONG Length,
PULONG PBytesTransferred) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->Read(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
Buffer, Offset, Length, PBytesTransferred);)
}
static NTSTATUS Write(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
PVOID Buffer, UINT64 Offset, ULONG Length,
BOOLEAN WriteToEndOfFile, BOOLEAN ConstrainedIo,
PULONG PBytesTransferred,
FSP_FSCTL_FILE_INFO *FileInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->Write(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
Buffer, Offset, Length, WriteToEndOfFile, ConstrainedIo,
PBytesTransferred, FileInfo);)
}
static NTSTATUS Flush(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
FSP_FSCTL_FILE_INFO *FileInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->Flush(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileInfo);)
}
static NTSTATUS GetFileInfo(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
FSP_FSCTL_FILE_INFO *FileInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->GetFileInfo(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileInfo);)
}
static NTSTATUS SetBasicInfo(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
UINT32 FileAttributes, UINT64 CreationTime,
UINT64 LastAccessTime, UINT64 LastWriteTime,
UINT64 ChangeTime,
FSP_FSCTL_FILE_INFO *FileInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->SetBasicInfo(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileAttributes, CreationTime, LastAccessTime, LastWriteTime, ChangeTime,
FileInfo);)
}
static NTSTATUS SetFileSize(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
UINT64 NewSize, BOOLEAN SetAllocationSize,
FSP_FSCTL_FILE_INFO *FileInfo) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->SetFileSize(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
NewSize, SetAllocationSize, FileInfo);)
}
static NTSTATUS CanDelete(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
PWSTR FileName) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->CanDelete(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileName);)
}
static NTSTATUS Rename(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
PWSTR FileName, PWSTR NewFileName,
BOOLEAN ReplaceIfExists) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->Rename(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileName, NewFileName, ReplaceIfExists);)
}
static NTSTATUS GetSecurity(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
PSECURITY_DESCRIPTOR SecurityDescriptor,
SIZE_T *PSecurityDescriptorSize) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->GetSecurity(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
SecurityDescriptor, PSecurityDescriptorSize);)
}
static NTSTATUS SetSecurity(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR ModificationDescriptor) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->SetSecurity(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
SecurityInformation, ModificationDescriptor);)
}
static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
PWSTR Pattern, PWSTR Marker, PVOID Buffer,
ULONG Length, PULONG PBytesTransferred) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->ReadDirectory(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
Pattern, Marker, Buffer, Length, PBytesTransferred);)
}
static NTSTATUS ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem0,
PWSTR FileName, UINT32 ReparsePointIndex,
BOOLEAN ResolveLastPathComponent,
PIO_STATUS_BLOCK PIoStatus, PVOID Buffer,
PSIZE_T PSize) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->ResolveReparsePoints(
FileName, ReparsePointIndex, ResolveLastPathComponent, PIoStatus,
Buffer, PSize);)
}
static NTSTATUS GetReparsePoint(FSP_FILE_SYSTEM *FileSystem0,
PVOID FullContext, PWSTR FileName,
PVOID Buffer, PSIZE_T PSize) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->GetReparsePoint(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileName, Buffer, PSize);)
}
static NTSTATUS SetReparsePoint(FSP_FILE_SYSTEM *FileSystem0,
PVOID FullContext, PWSTR FileName,
PVOID Buffer, SIZE_T Size) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->SetReparsePoint(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileName, Buffer, Size);)
}
static NTSTATUS DeleteReparsePoint(FSP_FILE_SYSTEM *FileSystem0,
PVOID FullContext, PWSTR FileName,
PVOID Buffer, SIZE_T Size) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->DeleteReparsePoint(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
FileName, Buffer, Size);)
}
static NTSTATUS GetStreamInfo(FSP_FILE_SYSTEM *FileSystem0, PVOID FullContext,
PVOID Buffer, ULONG Length,
PULONG PBytesTransferred) {
FileSystemBase *self = (FileSystemBase *)FileSystem0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->GetStreamInfo(
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext,
(PVOID)(UINT_PTR)((FSP_FSCTL_TRANSACT_FULL_CONTEXT *)FullContext)
->UserContext2,
Buffer, Length, PBytesTransferred);)
}
static FSP_FILE_SYSTEM_INTERFACE *Interface() {
static FSP_FILE_SYSTEM_INTERFACE _Interface = {
GetVolumeInfo,
SetVolumeLabel_,
GetSecurityByName,
Create,
Open,
Overwrite,
Cleanup,
Close,
Read,
Write,
Flush,
GetFileInfo,
SetBasicInfo,
SetFileSize,
CanDelete,
Rename,
GetSecurity,
SetSecurity,
ReadDirectory,
ResolveReparsePoints,
GetReparsePoint,
SetReparsePoint,
DeleteReparsePoint,
GetStreamInfo,
};
return &_Interface;
}
private:
/* disallow copy and assignment */
FileSystemHost(const FileSystemHost &);
FileSystemHost &operator=(const FileSystemHost &);
private:
FSP_FSCTL_VOLUME_PARAMS _VolumeParams;
FSP_FILE_SYSTEM *_FileSystemPtr;
FileSystemBase *_FileSystem;
};
class Service {
public:
/* ctor/dtor */
Service(PWSTR ServiceName) : _Service(0) {
Initialize();
FspServiceCreate(ServiceName, OnStart, OnStop, 0, &_Service);
if (0 != _Service)
_Service->UserContext = this;
}
virtual ~Service() {
if (0 != _Service)
FspServiceDelete(_Service);
}
/* control */
ULONG Run() {
if (0 == _Service) {
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service cannot be created (Status=%lx).",
STATUS_INSUFFICIENT_RESOURCES);
return FspWin32FromNtStatus(STATUS_INSUFFICIENT_RESOURCES);
}
FspServiceAllowConsoleMode(_Service);
NTSTATUS Result = FspServiceLoop(_Service);
ULONG ExitCode = FspServiceGetExitCode(_Service);
if (!NT_SUCCESS(Result)) {
FspServiceLog(EVENTLOG_ERROR_TYPE,
L"The service has failed to run (Status=%lx).", Result);
return FspWin32FromNtStatus(Result);
}
return ExitCode;
}
VOID Stop() {
if (0 == _Service)
return;
FspServiceStop(_Service);
}
VOID RequestTime(ULONG Time) {
if (0 == _Service)
return;
FspServiceRequestTime(_Service, Time);
}
ULONG GetExitCode() {
return 0 != _Service ? FspServiceGetExitCode(_Service)
: ERROR_NO_SYSTEM_RESOURCES;
}
VOID SetExitCode(ULONG ExitCode) {
if (0 == _Service)
return;
FspServiceSetExitCode(_Service, ExitCode);
}
FSP_SERVICE *ServiceHandle() { return _Service; }
static VOID Log(ULONG Type, PWSTR Format, ...) {
va_list ap;
va_start(ap, Format);
FspServiceLogV(Type, Format, ap);
va_end(ap);
}
static VOID LogV(ULONG Type, PWSTR Format, va_list ap) {
FspServiceLogV(Type, Format, ap);
}
protected:
/* start/stop */
virtual NTSTATUS ExceptionHandler() {
return 0xE06D7363 /*STATUS_CPP_EH_EXCEPTION*/;
}
virtual NTSTATUS OnStart(ULONG Argc, PWSTR *Argv) { return STATUS_SUCCESS; }
virtual NTSTATUS OnStop() { return STATUS_SUCCESS; }
private:
/* callbacks */
static NTSTATUS OnStart(FSP_SERVICE *Service0, ULONG Argc, PWSTR *Argv) {
Service *self = (Service *)Service0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->OnStart(Argc, Argv);)
}
static NTSTATUS OnStop(FSP_SERVICE *Service0) {
Service *self = (Service *)Service0->UserContext;
FSP_CPP_EXCEPTION_GUARD(return self->OnStop();)
}
private:
/* disallow copy and assignment */
Service(const Service &);
Service &operator=(const Service &);
private:
FSP_SERVICE *_Service;
};
} // namespace Fsp
#undef FSP_CPP_EXCEPTION_GUARD
#undef FSP_CPP_EXCEPTION_GUARD_VOID
#endif