v2.0.2-rc (#27)
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
## v2.0.2-rc ### BREAKING CHANGES * Refactored `config.json` - will need to verify configuration settings prior to mounting ### Issues * \#12 \[Unit Test\] Complete all providers unit tests * \#14 \[Unit Test\] SQLite mini-ORM unit tests and cleanup * \#16 Add support for bucket name in Sia provider * \#17 Update to common c++ build system * A single 64-bit Linux Jenkins server is used to build all Linux and Windows versions * All dependency sources are now included * MSVC is no longer supported * MSYS2 is required for building Windows binaries on Windows * OS X support is temporarily disabled * \#19 \[bug\] Rename file is broken for files that are existing * \#23 \[bug\] Incorrect file size displayed while upload is pending * \#24 RocksDB implementations should be transactional * \#25 Writes should block when maximum cache size is reached * \#26 Complete ring buffer and direct download support ### Changes from v2.0.1-rc * Ability to choose between RocksDB and SQLite databases * Added direct reads and implemented download fallback * Corrected file times on S3 and Sia providers * Corrected handling of `chown()` and `chmod()` * Fixed erroneous download of chunks after resize Reviewed-on: #27
This commit is contained in:
839
support/3rd_party/winfsp-2.0/inc/winfsp/fsctl.h
vendored
Normal file
839
support/3rd_party/winfsp-2.0/inc/winfsp/fsctl.h
vendored
Normal file
@ -0,0 +1,839 @@
|
||||
/**
|
||||
* @file winfsp/fsctl.h
|
||||
*
|
||||
* @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_FSCTL_H_INCLUDED
|
||||
#define WINFSP_FSCTL_H_INCLUDED
|
||||
|
||||
#include <devioctl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* static_assert is a C++11 feature, but seems to work with C on MSVC 2015 */
|
||||
#if defined(WINFSP_SYS_INTERNAL) || defined(WINFSP_DLL_INTERNAL)
|
||||
#define FSP_FSCTL_STATIC_ASSERT(e, m) static_assert(e, m)
|
||||
#else
|
||||
#define FSP_FSCTL_STATIC_ASSERT(e, m) static_assert(1, "")
|
||||
#endif
|
||||
|
||||
#define FSP_FSCTL_STR(x) FSP_FSCTL_STR_(x)
|
||||
#define FSP_FSCTL_STR_(x) #x
|
||||
#if defined(MyProductName)
|
||||
#define FSP_FSCTL_PRODUCT_NAME FSP_FSCTL_STR(MyProductName)
|
||||
#else
|
||||
#define FSP_FSCTL_PRODUCT_NAME "WinFsp"
|
||||
#endif
|
||||
#if defined(MyProductFileName)
|
||||
#define FSP_FSCTL_PRODUCT_FILE_NAME FSP_FSCTL_STR(MyProductFileName)
|
||||
#else
|
||||
#define FSP_FSCTL_PRODUCT_FILE_NAME "winfsp"
|
||||
#endif
|
||||
|
||||
#define FSP_FSCTL_DRIVER_NAME FSP_FSCTL_PRODUCT_NAME
|
||||
#define FSP_FSCTL_DISK_DEVICE_NAME FSP_FSCTL_DRIVER_NAME ".Disk"
|
||||
#define FSP_FSCTL_NET_DEVICE_NAME FSP_FSCTL_DRIVER_NAME ".Net"
|
||||
#define FSP_FSCTL_MUP_DEVICE_NAME FSP_FSCTL_DRIVER_NAME ".Mup"
|
||||
|
||||
#if defined(MyFspFsctlDeviceClassGuid)
|
||||
extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid =
|
||||
MyFspFsctlDeviceClassGuid;
|
||||
#else
|
||||
extern const __declspec(selectany) GUID FspFsctlDeviceClassGuid = {
|
||||
0x6f9d25fa,
|
||||
0x6dee,
|
||||
0x4a9d,
|
||||
{0x80, 0xf5, 0xe9, 0x8e, 0x14, 0xf3, 0x5e, 0x54}};
|
||||
#endif
|
||||
#if defined(MyFspFsvrtDeviceClassGuid)
|
||||
extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid =
|
||||
MyFspFsvrtDeviceClassGuid;
|
||||
#else
|
||||
extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid = {
|
||||
0xb48171c3,
|
||||
0xdd50,
|
||||
0x4852,
|
||||
{0x83, 0xa3, 0x34, 0x4c, 0x50, 0xd9, 0x3b, 0x17}};
|
||||
#endif
|
||||
|
||||
/* locations */
|
||||
#define FSP_FSCTL_PRODUCT_REGKEY "Software\\" FSP_FSCTL_PRODUCT_NAME
|
||||
#define FSP_FSCTL_PRODUCT_REGKEY_WOW64 KEY_WOW64_32KEY
|
||||
#if defined(_ARM64_)
|
||||
#define FSP_FSCTL_PRODUCT_FULL_REGKEY \
|
||||
"Software\\WOW6432Node\\" FSP_FSCTL_PRODUCT_NAME
|
||||
#define FSP_FSCTL_PRODUCT_FILE_ARCH "a64"
|
||||
#elif defined(_AMD64_)
|
||||
#define FSP_FSCTL_PRODUCT_FULL_REGKEY \
|
||||
"Software\\WOW6432Node\\" FSP_FSCTL_PRODUCT_NAME
|
||||
#define FSP_FSCTL_PRODUCT_FILE_ARCH "x64"
|
||||
#elif defined(_X86_)
|
||||
#define FSP_FSCTL_PRODUCT_FULL_REGKEY "Software\\" FSP_FSCTL_PRODUCT_NAME
|
||||
#define FSP_FSCTL_PRODUCT_FILE_ARCH "x86"
|
||||
#else
|
||||
#error unknown architecture
|
||||
#endif
|
||||
|
||||
/* alignment macros */
|
||||
#define FSP_FSCTL_ALIGN_UP(x, s) (((x) + ((s)-1L)) & ~((s)-1L))
|
||||
#define FSP_FSCTL_DEFAULT_ALIGNMENT 8
|
||||
#define FSP_FSCTL_DEFAULT_ALIGN_UP(x) \
|
||||
FSP_FSCTL_ALIGN_UP(x, FSP_FSCTL_DEFAULT_ALIGNMENT)
|
||||
#define FSP_FSCTL_DECLSPEC_ALIGN __declspec(align(FSP_FSCTL_DEFAULT_ALIGNMENT))
|
||||
|
||||
/* fsctl device codes */
|
||||
#define FSP_FSCTL_MOUNTDEV \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'M', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_MOUNTMGR \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'm', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_VOLUME_NAME \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'N', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_VOLUME_LIST \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'L', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_TRANSACT \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'T', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_IOCTL_TRANSACT \
|
||||
CTL_CODE(0x8000 | ('F' << 8) | 'W', 0x800 + 'T', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_TRANSACT_BATCH \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 't', METHOD_OUT_DIRECT, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_IOCTL_TRANSACT_BATCH \
|
||||
CTL_CODE(0x8000 | ('F' << 8) | 'W', 0x800 + 't', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_STOP \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'S', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_STOP0 \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 's', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_NOTIFY \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'n', METHOD_NEITHER, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_FSCTL_UNLOAD \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'U', METHOD_NEITHER, \
|
||||
FILE_ANY_ACCESS)
|
||||
|
||||
/* fsctl internal device codes (usable only in-kernel) */
|
||||
#define FSP_FSCTL_TRANSACT_INTERNAL \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + 'I', METHOD_NEITHER, \
|
||||
FILE_ANY_ACCESS)
|
||||
#define FSP_IOCTL_TRANSACT_INTERNAL \
|
||||
CTL_CODE(0x8000 | ('F' << 8) | 'W', 0x800 + 'I', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
|
||||
/* fsvol device codes */
|
||||
#define FSP_FSCTL_QUERY_WINFSP \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0x800 + '?', METHOD_BUFFERED, \
|
||||
FILE_ANY_ACCESS)
|
||||
|
||||
#define FSP_FSCTL_VOLUME_PARAMS_PREFIX "\\VolumeParams="
|
||||
|
||||
#define FSP_FSCTL_VOLUME_NAME_SIZE (64 * sizeof(WCHAR))
|
||||
#define FSP_FSCTL_VOLUME_PREFIX_SIZE (192 * sizeof(WCHAR))
|
||||
#define FSP_FSCTL_VOLUME_FSNAME_SIZE (16 * sizeof(WCHAR))
|
||||
#define FSP_FSCTL_VOLUME_NAME_SIZEMAX \
|
||||
(FSP_FSCTL_VOLUME_NAME_SIZE + FSP_FSCTL_VOLUME_PREFIX_SIZE)
|
||||
FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
|
||||
"Max volume name size is greater than MAX_PATH.");
|
||||
|
||||
#define FSP_FSCTL_TRANSACT_PATH_SIZEMAX (1024 * sizeof(WCHAR))
|
||||
|
||||
#define FSP_FSCTL_TRANSACT_REQ_SIZEMAX \
|
||||
(16 * 1024 - 64) /* 64: size for internal request header */
|
||||
#define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (16 * 1024)
|
||||
#define FSP_FSCTL_TRANSACT_REQ_BUFFER_SIZEMAX \
|
||||
(FSP_FSCTL_TRANSACT_REQ_SIZEMAX - sizeof(FSP_FSCTL_TRANSACT_REQ))
|
||||
#define FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX \
|
||||
(FSP_FSCTL_TRANSACT_RSP_SIZEMAX - sizeof(FSP_FSCTL_TRANSACT_RSP))
|
||||
#define FSP_FSCTL_TRANSACT_BATCH_BUFFER_SIZEMIN (64 * 1024)
|
||||
#define FSP_FSCTL_TRANSACT_BUFFER_SIZEMIN FSP_FSCTL_TRANSACT_REQ_SIZEMAX
|
||||
|
||||
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_HANDLE(T) \
|
||||
((HANDLE)((UINT_PTR)((T) & 0xffffffff)))
|
||||
#define FSP_FSCTL_TRANSACT_REQ_TOKEN_PID(T) ((UINT32)(((T) >> 32) & 0xffffffff))
|
||||
|
||||
#define FSP_FSCTL_DEVICECONTROL_SIZEMAX \
|
||||
(4 * 1024) /* must be < FSP_FSCTL_TRANSACT_{REQ,RSP}_SIZEMAX */
|
||||
|
||||
/* marshalling */
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4200 4201) /* zero-sized array in struct/union; \
|
||||
nameless struct/union */
|
||||
enum {
|
||||
FspFsctlTransactReservedKind = 0,
|
||||
FspFsctlTransactCreateKind,
|
||||
FspFsctlTransactOverwriteKind,
|
||||
FspFsctlTransactCleanupKind,
|
||||
FspFsctlTransactCloseKind,
|
||||
FspFsctlTransactReadKind,
|
||||
FspFsctlTransactWriteKind,
|
||||
FspFsctlTransactQueryInformationKind,
|
||||
FspFsctlTransactSetInformationKind,
|
||||
FspFsctlTransactQueryEaKind,
|
||||
FspFsctlTransactSetEaKind,
|
||||
FspFsctlTransactFlushBuffersKind,
|
||||
FspFsctlTransactQueryVolumeInformationKind,
|
||||
FspFsctlTransactSetVolumeInformationKind,
|
||||
FspFsctlTransactQueryDirectoryKind,
|
||||
FspFsctlTransactFileSystemControlKind,
|
||||
FspFsctlTransactDeviceControlKind,
|
||||
FspFsctlTransactShutdownKind,
|
||||
FspFsctlTransactLockControlKind,
|
||||
FspFsctlTransactQuerySecurityKind,
|
||||
FspFsctlTransactSetSecurityKind,
|
||||
FspFsctlTransactQueryStreamInformationKind,
|
||||
FspFsctlTransactKindCount,
|
||||
};
|
||||
enum {
|
||||
FspFsctlTransactTimeoutMinimum = 1000,
|
||||
FspFsctlTransactTimeoutMaximum = 10000,
|
||||
FspFsctlTransactTimeoutDefault =
|
||||
1000, /* DEPRECATED: default is unspecified */
|
||||
FspFsctlIrpTimeoutMinimum = 60000,
|
||||
FspFsctlIrpTimeoutMaximum = 600000,
|
||||
FspFsctlIrpTimeoutDefault = 300000,
|
||||
FspFsctlIrpTimeoutDebug = 142, /* special value for IRP timeout testing */
|
||||
FspFsctlIrpCapacityMinimum = 100,
|
||||
FspFsctlIrpCapacityMaximum = 1000,
|
||||
FspFsctlIrpCapacityDefault = 1000,
|
||||
};
|
||||
#define FSP_FSCTL_VOLUME_PARAMS_V0_FIELD_DEFN \
|
||||
UINT16 Version; /* set to 0 or sizeof(FSP_FSCTL_VOLUME_PARAMS) */ \
|
||||
/* volume information */ \
|
||||
UINT16 SectorSize; \
|
||||
UINT16 SectorsPerAllocationUnit; \
|
||||
UINT16 MaxComponentLength; /* maximum file name component length (bytes) */ \
|
||||
UINT64 VolumeCreationTime; \
|
||||
UINT32 VolumeSerialNumber; \
|
||||
/* I/O timeouts, capacity, etc. */ \
|
||||
UINT32 TransactTimeout; /* DEPRECATED: (millis; 1 sec - 10 sec) */ \
|
||||
UINT32 IrpTimeout; /* pending IRP timeout (millis; 1 min - 10 min) */ \
|
||||
UINT32 IrpCapacity; /* maximum number of pending IRP's (100 - 1000)*/ \
|
||||
UINT32 FileInfoTimeout; /* FileInfo/Security/VolumeInfo timeout (millis) */ \
|
||||
/* FILE_FS_ATTRIBUTE_INFORMATION::FileSystemAttributes */ \
|
||||
UINT32 CaseSensitiveSearch : 1; /* file system supports case-sensitive file \
|
||||
names */ \
|
||||
UINT32 CasePreservedNames : 1; /* file system preserves the case of file \
|
||||
names */ \
|
||||
UINT32 UnicodeOnDisk : 1; /* file system supports Unicode in file names */ \
|
||||
UINT32 PersistentAcls : 1; /* file system preserves and enforces access \
|
||||
control lists */ \
|
||||
UINT32 ReparsePoints : 1; /* file system supports reparse points */ \
|
||||
UINT32 ReparsePointsAccessCheck : 1; /* file system performs reparse point \
|
||||
access checks */ \
|
||||
UINT32 NamedStreams : 1; /* file system supports named streams */ \
|
||||
UINT32 HardLinks : 1; /* unimplemented; set to 0 */ \
|
||||
UINT32 \
|
||||
ExtendedAttributes: \
|
||||
1; /* file system supports extended attributes */ \
|
||||
UINT32 ReadOnlyVolume : 1; \
|
||||
/* kernel-mode flags */ \
|
||||
UINT32 PostCleanupWhenModifiedOnly : 1; /* post Cleanup when a file was \
|
||||
modified/deleted */ \
|
||||
UINT32 PassQueryDirectoryPattern : 1; /* pass Pattern during QueryDirectory \
|
||||
operations */ \
|
||||
UINT32 AlwaysUseDoubleBuffering : 1; \
|
||||
UINT32 \
|
||||
PassQueryDirectoryFileName: \
|
||||
1; /* pass FileName during QueryDirectory \
|
||||
(GetDirInfoByName) */ \
|
||||
UINT32 FlushAndPurgeOnCleanup : 1; /* keeps file off "standby" list */ \
|
||||
UINT32 DeviceControl : 1; /* support user-mode ioctl handling */ \
|
||||
/* user-mode flags */ \
|
||||
UINT32 UmFileContextIsUserContext2 : 1; /* user mode: FileContext parameter \
|
||||
is UserContext2 */ \
|
||||
UINT32 UmFileContextIsFullContext : 1; /* user mode: FileContext parameter \
|
||||
is FullContext */ \
|
||||
UINT32 UmNoReparsePointsDirCheck : 1; /* user mode: no dir option check for \
|
||||
reparse points */ \
|
||||
UINT32 UmReservedFlags : 5; \
|
||||
/* additional kernel-mode flags */ \
|
||||
UINT32 AllowOpenInKernelMode : 1; /* allow kernel mode to open files when \
|
||||
possible */ \
|
||||
UINT32 CasePreservedExtendedAttributes : 1; /* preserve case of EA (default \
|
||||
is UPPERCASE) */ \
|
||||
UINT32 WslFeatures : 1; /* support features required for WSLinux */ \
|
||||
UINT32 DirectoryMarkerAsNextOffset : 1; /* directory marker is next offset \
|
||||
instead of last name */ \
|
||||
UINT32 RejectIrpPriorToTransact0 : 1; /* DEPRECATED: reject IRP's prior to \
|
||||
FspFsctlTransact0 */ \
|
||||
UINT32 SupportsPosixUnlinkRename : 1; /* file system supports POSIX-style \
|
||||
unlink and rename */ \
|
||||
UINT32 PostDispositionWhenNecessaryOnly : 1; /* post Disposition for dirs or \
|
||||
READONLY attr check */ \
|
||||
UINT32 KmReservedFlags : 1; \
|
||||
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / \
|
||||
sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */ \
|
||||
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
|
||||
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN \
|
||||
/* additional fields; specify .Version == sizeof(FSP_FSCTL_VOLUME_PARAMS) */ \
|
||||
UINT32 VolumeInfoTimeoutValid : 1; /* VolumeInfoTimeout field is valid */ \
|
||||
UINT32 DirInfoTimeoutValid : 1; /* DirInfoTimeout field is valid */ \
|
||||
UINT32 SecurityTimeoutValid : 1; /* SecurityTimeout field is valid*/ \
|
||||
UINT32 StreamInfoTimeoutValid : 1; /* StreamInfoTimeout field is valid */ \
|
||||
UINT32 EaTimeoutValid : 1; /* EaTimeout field is valid */ \
|
||||
UINT32 KmAdditionalReservedFlags : 27; \
|
||||
UINT32 VolumeInfoTimeout; /* volume info timeout (millis); overrides \
|
||||
FileInfoTimeout */ \
|
||||
UINT32 DirInfoTimeout; /* dir info timeout (millis); overrides \
|
||||
FileInfoTimeout */ \
|
||||
UINT32 SecurityTimeout; /* security info timeout (millis); overrides \
|
||||
FileInfoTimeout */ \
|
||||
UINT32 StreamInfoTimeout; /* stream info timeout (millis); overrides \
|
||||
FileInfoTimeout */ \
|
||||
UINT32 EaTimeout; /* EA timeout (millis); overrides FileInfoTimeout */ \
|
||||
UINT32 FsextControlCode; \
|
||||
UINT32 Reserved32[1]; \
|
||||
UINT64 Reserved64[2];
|
||||
typedef struct {
|
||||
FSP_FSCTL_VOLUME_PARAMS_V0_FIELD_DEFN
|
||||
} FSP_FSCTL_VOLUME_PARAMS_V0;
|
||||
FSP_FSCTL_STATIC_ASSERT(
|
||||
456 == sizeof(FSP_FSCTL_VOLUME_PARAMS_V0),
|
||||
"sizeof(FSP_FSCTL_VOLUME_PARAMS_V0) must be exactly 456.");
|
||||
typedef struct {
|
||||
FSP_FSCTL_VOLUME_PARAMS_V0_FIELD_DEFN
|
||||
FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN
|
||||
} FSP_FSCTL_VOLUME_PARAMS;
|
||||
FSP_FSCTL_STATIC_ASSERT(504 == sizeof(FSP_FSCTL_VOLUME_PARAMS),
|
||||
"sizeof(FSP_FSCTL_VOLUME_PARAMS) is currently 504. "
|
||||
"Update this assertion check if it changes.");
|
||||
typedef struct {
|
||||
UINT64 TotalSize;
|
||||
UINT64 FreeSize;
|
||||
UINT16 VolumeLabelLength;
|
||||
WCHAR VolumeLabel[32];
|
||||
} FSP_FSCTL_VOLUME_INFO;
|
||||
FSP_FSCTL_STATIC_ASSERT(88 == sizeof(FSP_FSCTL_VOLUME_INFO),
|
||||
"sizeof(FSP_FSCTL_VOLUME_INFO) must be exactly 88.");
|
||||
typedef struct {
|
||||
UINT32 FileAttributes;
|
||||
UINT32 ReparseTag;
|
||||
UINT64 AllocationSize;
|
||||
UINT64 FileSize;
|
||||
UINT64 CreationTime;
|
||||
UINT64 LastAccessTime;
|
||||
UINT64 LastWriteTime;
|
||||
UINT64 ChangeTime;
|
||||
UINT64 IndexNumber;
|
||||
UINT32 HardLinks; /* unimplemented: set to 0 */
|
||||
UINT32 EaSize;
|
||||
} FSP_FSCTL_FILE_INFO;
|
||||
FSP_FSCTL_STATIC_ASSERT(72 == sizeof(FSP_FSCTL_FILE_INFO),
|
||||
"sizeof(FSP_FSCTL_FILE_INFO) must be exactly 72.");
|
||||
typedef struct {
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
PWSTR NormalizedName;
|
||||
UINT16 NormalizedNameSize;
|
||||
} FSP_FSCTL_OPEN_FILE_INFO;
|
||||
typedef struct {
|
||||
UINT16 Size;
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
union {
|
||||
UINT64 NextOffset;
|
||||
UINT8 Padding[24];
|
||||
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place
|
||||
* copying */
|
||||
} DUMMYUNIONNAME;
|
||||
WCHAR FileNameBuf[];
|
||||
} FSP_FSCTL_DIR_INFO;
|
||||
FSP_FSCTL_STATIC_ASSERT(104 == sizeof(FSP_FSCTL_DIR_INFO),
|
||||
"sizeof(FSP_FSCTL_DIR_INFO) must be exactly 104.");
|
||||
typedef struct {
|
||||
UINT16 Size;
|
||||
UINT64 StreamSize;
|
||||
UINT64 StreamAllocationSize;
|
||||
WCHAR StreamNameBuf[];
|
||||
} FSP_FSCTL_STREAM_INFO;
|
||||
FSP_FSCTL_STATIC_ASSERT(24 == sizeof(FSP_FSCTL_STREAM_INFO),
|
||||
"sizeof(FSP_FSCTL_STREAM_INFO) must be exactly 24.");
|
||||
typedef struct {
|
||||
UINT16 Size;
|
||||
UINT32 Filter;
|
||||
UINT32 Action;
|
||||
WCHAR FileNameBuf[];
|
||||
} FSP_FSCTL_NOTIFY_INFO;
|
||||
FSP_FSCTL_STATIC_ASSERT(12 == sizeof(FSP_FSCTL_NOTIFY_INFO),
|
||||
"sizeof(FSP_FSCTL_NOTIFY_INFO) must be exactly 12.");
|
||||
typedef struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
} FSP_FSCTL_TRANSACT_FULL_CONTEXT;
|
||||
typedef struct {
|
||||
UINT16 Offset;
|
||||
UINT16 Size;
|
||||
} FSP_FSCTL_TRANSACT_BUF;
|
||||
typedef struct {
|
||||
UINT16 Version;
|
||||
UINT16 Size;
|
||||
UINT32 Kind;
|
||||
UINT64 Hint;
|
||||
union {
|
||||
struct {
|
||||
UINT32 CreateOptions; /* Disposition: high 8 bits; Options: low 24 bits */
|
||||
UINT32 FileAttributes; /* file attributes for new files */
|
||||
FSP_FSCTL_TRANSACT_BUF
|
||||
SecurityDescriptor; /* security descriptor for new files */
|
||||
UINT64 AllocationSize; /* initial allocation size */
|
||||
UINT64 AccessToken; /* request access token (PID,HANDLE) */
|
||||
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
|
||||
FSP_FSCTL_TRANSACT_BUF
|
||||
Ea; /* extended attributes or reparse point buffer */
|
||||
UINT32 UserMode : 1; /* request originated in user mode */
|
||||
UINT32 HasTraversePrivilege : 1; /* requestor has
|
||||
TOKEN_HAS_TRAVERSE_PRIVILEGE */
|
||||
UINT32
|
||||
HasBackupPrivilege : 1; /* requestor has TOKEN_HAS_BACKUP_PRIVILEGE */
|
||||
UINT32 HasRestorePrivilege : 1; /* requestor has
|
||||
TOKEN_HAS_RESTORE_PRIVILEGE */
|
||||
UINT32 OpenTargetDirectory : 1; /* open target dir and report
|
||||
FILE_{EXISTS,DOES_NOT_EXIST} */
|
||||
UINT32
|
||||
CaseSensitive : 1; /* FileName comparisons should be case-sensitive */
|
||||
UINT32 HasTrailingBackslash : 1; /* FileName had trailing backslash */
|
||||
UINT32 AcceptsSecurityDescriptor : 1;
|
||||
UINT32 EaIsReparsePoint : 1; /* Ea buffer is reparse point */
|
||||
UINT32 ReservedFlags : 24;
|
||||
UINT16 NamedStream; /* request targets named stream; colon offset in
|
||||
FileName */
|
||||
} Create;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT32
|
||||
FileAttributes; /* file attributes for overwritten/superseded files */
|
||||
UINT64
|
||||
AllocationSize; /* allocation size for overwritten/superseded files */
|
||||
UINT32 Supersede : 1; /* 0: FILE_OVERWRITE operation, 1: FILE_SUPERSEDE
|
||||
operation */
|
||||
FSP_FSCTL_TRANSACT_BUF Ea; /* extended attributes buffer */
|
||||
} Overwrite;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT32 Delete : 1; /* file must be deleted */
|
||||
UINT32 SetAllocationSize : 1;
|
||||
UINT32 SetArchiveBit : 1;
|
||||
UINT32 SetLastAccessTime : 1;
|
||||
UINT32 SetLastWriteTime : 1;
|
||||
UINT32 SetChangeTime : 1;
|
||||
} Cleanup;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
} Close;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT64 Address;
|
||||
UINT64 Offset;
|
||||
UINT32 Length;
|
||||
UINT32 Key;
|
||||
} Read;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT64 Address;
|
||||
UINT64 Offset;
|
||||
UINT32 Length;
|
||||
UINT32 Key;
|
||||
UINT32 ConstrainedIo : 1;
|
||||
} Write;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
} QueryInformation;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT32 FileInformationClass;
|
||||
union {
|
||||
struct {
|
||||
UINT64 AllocationSize;
|
||||
} Allocation;
|
||||
struct {
|
||||
UINT32 FileAttributes;
|
||||
UINT64 CreationTime;
|
||||
UINT64 LastAccessTime;
|
||||
UINT64 LastWriteTime;
|
||||
UINT64 ChangeTime;
|
||||
} Basic;
|
||||
struct {
|
||||
UINT32 Delete : 1;
|
||||
} Disposition;
|
||||
struct {
|
||||
UINT32 Flags;
|
||||
} DispositionEx;
|
||||
struct {
|
||||
UINT64 FileSize;
|
||||
} EndOfFile;
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF NewFileName;
|
||||
UINT64 AccessToken; /* request access token (PID,HANDLE) */
|
||||
} Rename;
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF NewFileName;
|
||||
UINT64 AccessToken; /* request access token (PID,HANDLE) */
|
||||
UINT32 Flags;
|
||||
} RenameEx;
|
||||
} Info;
|
||||
} SetInformation;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
} QueryEa;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
FSP_FSCTL_TRANSACT_BUF Ea;
|
||||
} SetEa;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
} FlushBuffers;
|
||||
struct {
|
||||
UINT32 FsInformationClass;
|
||||
union {
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF VolumeLabel;
|
||||
} Label;
|
||||
} Info;
|
||||
} SetVolumeInformation;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT64 Address;
|
||||
UINT32 Length;
|
||||
FSP_FSCTL_TRANSACT_BUF Pattern;
|
||||
FSP_FSCTL_TRANSACT_BUF Marker;
|
||||
UINT32
|
||||
CaseSensitive : 1; /* FileName comparisons should be case-sensitive */
|
||||
UINT32 PatternIsFileName : 1; /* Pattern does not contain wildcards */
|
||||
} QueryDirectory;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT32 FsControlCode;
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
UINT16 TargetOnFileSystem; /* the target of the symbolic link is on this
|
||||
file system */
|
||||
} FileSystemControl;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT32 IoControlCode;
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
UINT32 OutputLength;
|
||||
} DeviceControl;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
} QuerySecurity;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
UINT32 SecurityInformation;
|
||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
||||
} SetSecurity;
|
||||
struct {
|
||||
UINT64 UserContext;
|
||||
UINT64 UserContext2;
|
||||
} QueryStreamInformation;
|
||||
} Req;
|
||||
FSP_FSCTL_TRANSACT_BUF FileName;
|
||||
/* Create,Cleanup,SetInformation{Disposition,Rename},FileSystemControl{ReparsePoint}
|
||||
*/
|
||||
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
||||
} FSP_FSCTL_TRANSACT_REQ;
|
||||
typedef struct {
|
||||
UINT16 Version;
|
||||
UINT16 Size;
|
||||
UINT32 Kind;
|
||||
UINT64 Hint;
|
||||
struct {
|
||||
UINT32 Information;
|
||||
UINT32 Status;
|
||||
} IoStatus;
|
||||
union {
|
||||
union {
|
||||
/* IoStatus.Status == STATUS_SUCCESS */
|
||||
struct {
|
||||
UINT64 UserContext; /* user context associated with file node */
|
||||
UINT64 UserContext2; /* user context associated with file descriptor
|
||||
(handle) */
|
||||
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
|
||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
FSP_FSCTL_TRANSACT_BUF FileName;
|
||||
UINT32 DisableCache : 1;
|
||||
UINT32 HasSecurityDescriptor : 1;
|
||||
} Opened;
|
||||
/* IoStatus.Status == STATUS_REPARSE */
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
} Reparse;
|
||||
} Create;
|
||||
struct {
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
} Overwrite;
|
||||
struct {
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
} Write;
|
||||
struct {
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
} QueryInformation;
|
||||
struct {
|
||||
FSP_FSCTL_FILE_INFO
|
||||
FileInfo; /* valid: File{Allocation,Basic,EndOfFile}Information */
|
||||
} SetInformation;
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF Ea;
|
||||
} QueryEa;
|
||||
struct {
|
||||
FSP_FSCTL_FILE_INFO FileInfo;
|
||||
FSP_FSCTL_TRANSACT_BUF
|
||||
Ea; /* Size==0 means no extended atttributed returned */
|
||||
} SetEa;
|
||||
struct {
|
||||
FSP_FSCTL_FILE_INFO FileInfo; /* valid when flushing file (not volume) */
|
||||
} FlushBuffers;
|
||||
struct {
|
||||
FSP_FSCTL_VOLUME_INFO VolumeInfo;
|
||||
} QueryVolumeInformation;
|
||||
struct {
|
||||
FSP_FSCTL_VOLUME_INFO VolumeInfo;
|
||||
} SetVolumeInformation;
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
} FileSystemControl;
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
} DeviceControl;
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor;
|
||||
} QuerySecurity;
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* Size==0 means no security
|
||||
descriptor returned */
|
||||
} SetSecurity;
|
||||
struct {
|
||||
FSP_FSCTL_TRANSACT_BUF Buffer;
|
||||
} QueryStreamInformation;
|
||||
} Rsp;
|
||||
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
|
||||
} FSP_FSCTL_TRANSACT_RSP;
|
||||
#pragma warning(pop)
|
||||
FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX >
|
||||
FSP_FSCTL_TRANSACT_PATH_SIZEMAX,
|
||||
"FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX must be greater "
|
||||
"than FSP_FSCTL_TRANSACT_PATH_SIZEMAX "
|
||||
"to detect when a normalized name has been set during "
|
||||
"a Create/Open request.");
|
||||
static inline BOOLEAN
|
||||
FspFsctlTransactCanProduceRequest(FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
PVOID RequestBufEnd) {
|
||||
return (PUINT8)Request + FSP_FSCTL_TRANSACT_REQ_SIZEMAX <=
|
||||
(PUINT8)RequestBufEnd;
|
||||
}
|
||||
static inline FSP_FSCTL_TRANSACT_REQ *
|
||||
FspFsctlTransactProduceRequest(FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
SIZE_T RequestSize) {
|
||||
PVOID NextRequest = (PUINT8)Request + FSP_FSCTL_DEFAULT_ALIGN_UP(RequestSize);
|
||||
return (FSP_FSCTL_TRANSACT_REQ *)NextRequest;
|
||||
}
|
||||
static inline FSP_FSCTL_TRANSACT_REQ *
|
||||
FspFsctlTransactConsumeRequest(FSP_FSCTL_TRANSACT_REQ *Request,
|
||||
PVOID RequestBufEnd) {
|
||||
if ((PUINT8)Request + sizeof(Request->Size) > (PUINT8)RequestBufEnd ||
|
||||
sizeof(FSP_FSCTL_TRANSACT_REQ) > Request->Size)
|
||||
return 0;
|
||||
PVOID NextRequest =
|
||||
(PUINT8)Request + FSP_FSCTL_DEFAULT_ALIGN_UP(Request->Size);
|
||||
return NextRequest <= RequestBufEnd ? (FSP_FSCTL_TRANSACT_REQ *)NextRequest
|
||||
: 0;
|
||||
}
|
||||
static inline BOOLEAN
|
||||
FspFsctlTransactCanProduceResponse(FSP_FSCTL_TRANSACT_RSP *Response,
|
||||
PVOID ResponseBufEnd) {
|
||||
return (PUINT8)Response + FSP_FSCTL_TRANSACT_RSP_SIZEMAX <=
|
||||
(PUINT8)ResponseBufEnd;
|
||||
}
|
||||
static inline FSP_FSCTL_TRANSACT_RSP *
|
||||
FspFsctlTransactProduceResponse(FSP_FSCTL_TRANSACT_RSP *Response,
|
||||
SIZE_T ResponseSize) {
|
||||
PVOID NextResponse =
|
||||
(PUINT8)Response + FSP_FSCTL_DEFAULT_ALIGN_UP(ResponseSize);
|
||||
return (FSP_FSCTL_TRANSACT_RSP *)NextResponse;
|
||||
}
|
||||
static inline FSP_FSCTL_TRANSACT_RSP *
|
||||
FspFsctlTransactConsumeResponse(FSP_FSCTL_TRANSACT_RSP *Response,
|
||||
PVOID ResponseBufEnd) {
|
||||
if ((PUINT8)Response + sizeof(Response->Size) > (PUINT8)ResponseBufEnd ||
|
||||
sizeof(FSP_FSCTL_TRANSACT_RSP) > Response->Size)
|
||||
return 0;
|
||||
PVOID NextResponse =
|
||||
(PUINT8)Response + FSP_FSCTL_DEFAULT_ALIGN_UP(Response->Size);
|
||||
return NextResponse <= ResponseBufEnd ? (FSP_FSCTL_TRANSACT_RSP *)NextResponse
|
||||
: 0;
|
||||
}
|
||||
|
||||
#if !defined(_KERNEL_MODE)
|
||||
FSP_API NTSTATUS FspFsctlCreateVolume(
|
||||
PWSTR DevicePath, const FSP_FSCTL_VOLUME_PARAMS *VolumeParams,
|
||||
PWCHAR VolumeNameBuf, SIZE_T VolumeNameSize, PHANDLE PVolumeHandle);
|
||||
FSP_API NTSTATUS FspFsctlMakeMountdev(HANDLE VolumeHandle, BOOLEAN Persistent,
|
||||
GUID *UniqueId);
|
||||
FSP_API NTSTATUS FspFsctlUseMountmgr(HANDLE VolumeHandle, PWSTR MountPoint);
|
||||
FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle, PVOID ResponseBuf,
|
||||
SIZE_T ResponseBufSize, PVOID RequestBuf,
|
||||
SIZE_T *PRequestBufSize, BOOLEAN Batch);
|
||||
FSP_API NTSTATUS FspFsctlStop(HANDLE VolumeHandle);
|
||||
FSP_API NTSTATUS FspFsctlStop0(HANDLE VolumeHandle);
|
||||
FSP_API NTSTATUS FspFsctlNotify(HANDLE VolumeHandle,
|
||||
FSP_FSCTL_NOTIFY_INFO *NotifyInfo, SIZE_T Size);
|
||||
FSP_API NTSTATUS FspFsctlGetVolumeList(PWSTR DevicePath, PWCHAR VolumeListBuf,
|
||||
PSIZE_T PVolumeListSize);
|
||||
FSP_API NTSTATUS FspFsctlPreflight(PWSTR DevicePath);
|
||||
FSP_API NTSTATUS FspFsctlStartService(VOID);
|
||||
FSP_API NTSTATUS FspFsctlStopService(VOID);
|
||||
FSP_API NTSTATUS FspFsctlEnumServices(VOID (*EnumFn)(PVOID Context,
|
||||
PWSTR ServiceName,
|
||||
BOOLEAN Running),
|
||||
PVOID Context);
|
||||
|
||||
typedef struct {
|
||||
/* in */
|
||||
HANDLE VolumeHandle; /* volume handle returned by FspFsctlCreateVolume */
|
||||
PWSTR VolumeName; /* volume name returned by FspFsctlCreateVolume */
|
||||
PSECURITY_DESCRIPTOR
|
||||
Security; /* optional: security descriptor for directories */
|
||||
UINT64 Reserved; /* reserved for future use */
|
||||
/* in/out */
|
||||
PWSTR MountPoint; /* FspMountSet sets drive in buffer when passed "*:" */
|
||||
HANDLE MountHandle; /* FspMountSet sets, FspMountRemove uses */
|
||||
} FSP_MOUNT_DESC;
|
||||
FSP_API NTSTATUS FspMountSet(FSP_MOUNT_DESC *Desc);
|
||||
FSP_API NTSTATUS FspMountRemove(FSP_MOUNT_DESC *Desc);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Atomics
|
||||
*
|
||||
* See https://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
|
||||
* (https://archive.is/mJfFX)
|
||||
*/
|
||||
#if _MSC_VER >= 1920 /* VS2019 or later */
|
||||
__int32 __iso_volatile_load32(const volatile __int32 *);
|
||||
void __iso_volatile_store32(volatile __int32 *, __int32);
|
||||
__int64 __iso_volatile_load64(const volatile __int64 *);
|
||||
void __iso_volatile_store64(volatile __int64 *, __int64);
|
||||
#define FSP_INTERLOCKED__LOAD32(p) __iso_volatile_load32(p)
|
||||
#define FSP_INTERLOCKED__STORE32(p, v) __iso_volatile_store32(p, v)
|
||||
#define FSP_INTERLOCKED__LOAD64(p) __iso_volatile_load64(p)
|
||||
#define FSP_INTERLOCKED__STORE64(p, v) __iso_volatile_store64(p, v)
|
||||
#else
|
||||
#define FSP_INTERLOCKED__LOAD32(p) (*(p))
|
||||
#define FSP_INTERLOCKED__STORE32(p, v) (*(p) = (v))
|
||||
#define FSP_INTERLOCKED__LOAD64(p) (*(p))
|
||||
#define FSP_INTERLOCKED__STORE64(p, v) (*(p) = (v))
|
||||
#endif
|
||||
static inline INT32 FspInterlockedLoad32(INT32 volatile *p) {
|
||||
#if defined(_M_ARM64)
|
||||
void __dmb(unsigned int);
|
||||
INT32 v = FSP_INTERLOCKED__LOAD32(p);
|
||||
__dmb(0xb);
|
||||
return v;
|
||||
|
||||
#elif defined(_M_X64) || defined(_M_IX86)
|
||||
#ifndef _ReadWriteBarrier
|
||||
void _ReadWriteBarrier(void);
|
||||
#endif
|
||||
INT32 v = FSP_INTERLOCKED__LOAD32(p);
|
||||
_ReadWriteBarrier();
|
||||
return v;
|
||||
|
||||
#endif
|
||||
}
|
||||
static inline VOID FspInterlockedStore32(INT32 volatile *p, INT32 v) {
|
||||
#if defined(_M_ARM64)
|
||||
void __dmb(unsigned int);
|
||||
__dmb(0xb);
|
||||
FSP_INTERLOCKED__STORE32(p, v);
|
||||
__dmb(0xb);
|
||||
|
||||
#elif defined(_M_X64) || defined(_M_IX86)
|
||||
long _InterlockedExchange(long volatile *, long);
|
||||
_InterlockedExchange((long volatile *)p, v);
|
||||
|
||||
#endif
|
||||
}
|
||||
static inline VOID *FspInterlockedLoadPointer(VOID *volatile *p) {
|
||||
#if defined(_M_ARM64)
|
||||
void __dmb(unsigned int);
|
||||
VOID *v = (VOID *)FSP_INTERLOCKED__LOAD64((__int64 volatile *)(p));
|
||||
__dmb(0xb);
|
||||
return v;
|
||||
|
||||
#elif defined(_M_X64)
|
||||
#ifndef _ReadWriteBarrier
|
||||
void _ReadWriteBarrier(void);
|
||||
#endif
|
||||
VOID *v = (VOID *)FSP_INTERLOCKED__LOAD64((__int64 volatile *)(p));
|
||||
_ReadWriteBarrier();
|
||||
return v;
|
||||
|
||||
#elif defined(_M_IX86)
|
||||
#ifndef _ReadWriteBarrier
|
||||
void _ReadWriteBarrier(void);
|
||||
#endif
|
||||
VOID *v = (VOID *)FSP_INTERLOCKED__LOAD32((__int32 volatile *)(p));
|
||||
_ReadWriteBarrier();
|
||||
return v;
|
||||
|
||||
#endif
|
||||
}
|
||||
static inline VOID FspInterlockedStorePointer(VOID *volatile *p, VOID *v) {
|
||||
#if defined(_M_ARM64)
|
||||
void __dmb(unsigned int);
|
||||
__dmb(0xb);
|
||||
FSP_INTERLOCKED__STORE64((__int64 volatile *)(p), (__int64)(v));
|
||||
__dmb(0xb);
|
||||
|
||||
#elif defined(_M_X64) || defined(_M_IX86)
|
||||
void *_InterlockedExchangePointer(void *volatile *, void *);
|
||||
_InterlockedExchangePointer(p, v);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
350
support/3rd_party/winfsp-2.0/inc/winfsp/launch.h
vendored
Normal file
350
support/3rd_party/winfsp-2.0/inc/winfsp/launch.h
vendored
Normal file
@ -0,0 +1,350 @@
|
||||
/**
|
||||
* @file winfsp/launch.h
|
||||
* WinFsp Launch API.
|
||||
*
|
||||
* In order to use the WinFsp Launch API a program must include <winfsp/launch.h>
|
||||
* and link with the winfsp_x64.dll (or winfsp_x86.dll) library.
|
||||
*
|
||||
* @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_LAUNCH_H_INCLUDED
|
||||
#define WINFSP_LAUNCH_H_INCLUDED
|
||||
|
||||
#include <winfsp/winfsp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FSP_LAUNCH_REGKEY FSP_FSCTL_PRODUCT_REGKEY "\\Services"
|
||||
#define FSP_LAUNCH_REGKEY_WOW64 FSP_FSCTL_PRODUCT_REGKEY_WOW64
|
||||
#define FSP_LAUNCH_FULL_REGKEY FSP_FSCTL_PRODUCT_FULL_REGKEY "\\Services"
|
||||
|
||||
#define FSP_LAUNCH_PIPE_NAME "\\\\.\\pipe\\" FSP_FSCTL_PRODUCT_NAME ".{14E7137D-22B4-437A-B0C1-D21D1BDF3767}"
|
||||
#define FSP_LAUNCH_PIPE_BUFFER_SIZE 4096
|
||||
#define FSP_LAUNCH_PIPE_OWNER ((PSID)WinLocalSystemSid)
|
||||
|
||||
/*
|
||||
* The launcher named pipe SDDL gives full access to LocalSystem and Administrators and
|
||||
* GENERIC_READ and FILE_WRITE_DATA access to Everyone. We are careful not to give the
|
||||
* FILE_CREATE_PIPE_INSTANCE right to Everyone to disallow the creation of additional
|
||||
* pipe instances.
|
||||
*/
|
||||
#define FSP_LAUNCH_PIPE_SDDL "O:SYG:SYD:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRDCCR;;;WD)"
|
||||
|
||||
/*
|
||||
* The default service instance SDDL gives full access to LocalSystem and Administrators.
|
||||
* The only possible service instance rights are as follows:
|
||||
* RP SERVICE_START
|
||||
* WP SERVICE_STOP
|
||||
* LC SERVICE_QUERY_STATUS
|
||||
*
|
||||
* To create a service that can be started, stopped or queried by Everyone, you can set
|
||||
* the following SDDL:
|
||||
* D:P(A;;RPWPLC;;;WD)
|
||||
*/
|
||||
#define FSP_LAUNCH_SERVICE_DEFAULT_SDDL "D:P(A;;RPWPLC;;;SY)(A;;RPWPLC;;;BA)"
|
||||
#define FSP_LAUNCH_SERVICE_WORLD_SDDL "D:P(A;;RPWPLC;;;WD)"
|
||||
|
||||
enum
|
||||
{
|
||||
FspLaunchCmdStart = 'S', /* requires: SERVICE_START */
|
||||
FspLaunchCmdStartWithSecret = 'X', /* requires: SERVICE_START */
|
||||
FspLaunchCmdStop = 'T', /* requires: SERVICE_STOP */
|
||||
FspLaunchCmdGetInfo = 'I', /* requires: SERVICE_QUERY_STATUS */
|
||||
FspLaunchCmdGetNameList = 'L', /* requires: none*/
|
||||
FspLaunchCmdDefineDosDevice = 'D', /* internal: do not use! */
|
||||
FspLaunchCmdQuit = 'Q', /* DEBUG version only */
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FspLaunchCmdSuccess = '$',
|
||||
FspLaunchCmdFailure = '!',
|
||||
};
|
||||
|
||||
/**
|
||||
* @group Launch Control
|
||||
*/
|
||||
/**
|
||||
* Call launcher pipe.
|
||||
*
|
||||
* This function is used to send a command to the launcher and receive a response.
|
||||
*
|
||||
* @param Command
|
||||
* Launcher command to send. For example, the 'L' launcher command instructs
|
||||
* the launcher to list all running service instances.
|
||||
* @param Argc
|
||||
* Command argument count. May be 0.
|
||||
* @param Argv
|
||||
* Command argument array. May be NULL.
|
||||
* @param Argl
|
||||
* Command argument length array. May be NULL. If this is NULL all command arguments
|
||||
* are assumed to be NULL-terminated strings. It is also possible for specific arguments
|
||||
* to be NULL-terminated; in this case pass -1 in the corresponding Argl position.
|
||||
* @param Buffer
|
||||
* Buffer that receives the command response. May be NULL.
|
||||
* @param PSize
|
||||
* Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
* contains the number of bytes transferred. May be NULL.
|
||||
* @param PLauncherError
|
||||
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
* @return
|
||||
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
* returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
* reported through PLauncherError.
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchCallLauncherPipe(
|
||||
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
|
||||
PWSTR Buffer, PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
/**
|
||||
* Call launcher pipe.
|
||||
*
|
||||
* This function is used to send a command to the launcher and receive a response.
|
||||
*
|
||||
* @param Command
|
||||
* Launcher command to send. For example, the 'L' launcher command instructs
|
||||
* the launcher to list all running service instances.
|
||||
* @param Argc
|
||||
* Command argument count. May be 0.
|
||||
* @param Argv
|
||||
* Command argument array. May be NULL.
|
||||
* @param Argl
|
||||
* Command argument length array. May be NULL. If this is NULL all command arguments
|
||||
* are assumed to be NULL-terminated strings. It is also possible for specific arguments
|
||||
* to be NULL-terminated; in this case pass -1 in the corresponding Argl position.
|
||||
* @param Buffer
|
||||
* Buffer that receives the command response. May be NULL.
|
||||
* @param PSize
|
||||
* Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
* contains the number of bytes transferred. May be NULL.
|
||||
* @param AllowImpersonation
|
||||
* Allow caller to be impersonated by launcher.
|
||||
* @param PLauncherError
|
||||
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
* @return
|
||||
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
* returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
* reported through PLauncherError.
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchCallLauncherPipeEx(
|
||||
WCHAR Command, ULONG Argc, PWSTR *Argv, ULONG *Argl,
|
||||
PWSTR Buffer, PULONG PSize,
|
||||
BOOLEAN AllowImpersonation,
|
||||
PULONG PLauncherError);
|
||||
/**
|
||||
* Start a service instance.
|
||||
*
|
||||
* @param ClassName
|
||||
* Class name of the service instance to start.
|
||||
* @param InstanceName
|
||||
* Instance name of the service instance to start.
|
||||
* @param Argc
|
||||
* Service instance argument count. May be 0.
|
||||
* @param Argv
|
||||
* Service instance argument array. May be NULL.
|
||||
* @param HasSecret
|
||||
* Whether the last argument in Argv is assumed to be a secret (e.g. password) or not.
|
||||
* Secrets are passed to service instances through standard input rather than the command
|
||||
* line.
|
||||
* @param PLauncherError
|
||||
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
* @return
|
||||
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
* returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
* reported through PLauncherError.
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchStart(
|
||||
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
|
||||
BOOLEAN HasSecret,
|
||||
PULONG PLauncherError);
|
||||
/**
|
||||
* Start a service instance.
|
||||
*
|
||||
* @param ClassName
|
||||
* Class name of the service instance to start.
|
||||
* @param InstanceName
|
||||
* Instance name of the service instance to start.
|
||||
* @param Argc
|
||||
* Service instance argument count. May be 0.
|
||||
* @param Argv
|
||||
* Service instance argument array. May be NULL.
|
||||
* @param HasSecret
|
||||
* Whether the last argument in Argv is assumed to be a secret (e.g. password) or not.
|
||||
* Secrets are passed to service instances through standard input rather than the command
|
||||
* line.
|
||||
* @param AllowImpersonation
|
||||
* Allow caller to be impersonated by launcher.
|
||||
* @param PLauncherError
|
||||
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
* @return
|
||||
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
* returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
* reported through PLauncherError.
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchStartEx(
|
||||
PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
|
||||
BOOLEAN HasSecret,
|
||||
BOOLEAN AllowImpersonation,
|
||||
PULONG PLauncherError);
|
||||
/**
|
||||
* Stop a service instance.
|
||||
*
|
||||
* @param ClassName
|
||||
* Class name of the service instance to stop.
|
||||
* @param InstanceName
|
||||
* Instance name of the service instance to stop.
|
||||
* @param PLauncherError
|
||||
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
* @return
|
||||
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
* returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
* reported through PLauncherError.
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchStop(
|
||||
PWSTR ClassName, PWSTR InstanceName,
|
||||
PULONG PLauncherError);
|
||||
/**
|
||||
* Get information about a service instance.
|
||||
*
|
||||
* The information is a list of NULL-terminated strings: the class name of the service instance,
|
||||
* the instance name of the service instance and the full command line used to start the service
|
||||
* instance.
|
||||
*
|
||||
* @param ClassName
|
||||
* Class name of the service instance to stop.
|
||||
* @param InstanceName
|
||||
* Instance name of the service instance to stop.
|
||||
* @param Buffer
|
||||
* Buffer that receives the command response. May be NULL.
|
||||
* @param PSize
|
||||
* Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
* contains the number of bytes transferred. May be NULL.
|
||||
* @param PLauncherError
|
||||
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
* @return
|
||||
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
* returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
* reported through PLauncherError.
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchGetInfo(
|
||||
PWSTR ClassName, PWSTR InstanceName,
|
||||
PWSTR Buffer, PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
/**
|
||||
* List service instances.
|
||||
*
|
||||
* The information is a list of pairs of NULL-terminated strings. Each pair contains the class
|
||||
* name and instance name of a service instance. All currently running service instances are
|
||||
* listed.
|
||||
*
|
||||
* @param Buffer
|
||||
* Buffer that receives the command response. May be NULL.
|
||||
* @param PSize
|
||||
* Pointer to a ULONG. On input it contains the size of the Buffer. On output it
|
||||
* contains the number of bytes transferred. May be NULL.
|
||||
* @param PLauncherError
|
||||
* Receives the launcher error if any. This is always a Win32 error code. May not be NULL.
|
||||
* @return
|
||||
* STATUS_SUCCESS if the command is sent successfully to the launcher, even if the launcher
|
||||
* returns an error. Other status codes indicate a communication error. Launcher errors are
|
||||
* reported through PLauncherError.
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchGetNameList(
|
||||
PWSTR Buffer, PULONG PSize,
|
||||
PULONG PLauncherError);
|
||||
|
||||
/**
|
||||
* @group Service Registry
|
||||
*/
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
||||
/**
|
||||
* Service registry record.
|
||||
*/
|
||||
typedef struct _FSP_LAUNCH_REG_RECORD
|
||||
{
|
||||
PWSTR Agent;
|
||||
PWSTR Executable;
|
||||
PWSTR CommandLine;
|
||||
PWSTR WorkDirectory;
|
||||
PWSTR RunAs;
|
||||
PWSTR Security;
|
||||
PWSTR AuthPackage;
|
||||
PWSTR Stderr;
|
||||
PVOID Reserved0[4];
|
||||
ULONG JobControl;
|
||||
ULONG Credentials;
|
||||
ULONG AuthPackageId;
|
||||
ULONG Recovery;
|
||||
ULONG Reserved1[4];
|
||||
UINT8 Buffer[];
|
||||
} FSP_LAUNCH_REG_RECORD;
|
||||
#pragma warning(pop)
|
||||
/**
|
||||
* Add/change/delete a service registry record.
|
||||
*
|
||||
* @param ClassName
|
||||
* The service class name.
|
||||
* @param Record
|
||||
* The record to set in the registry. If NULL, the registry record is deleted.
|
||||
* @return
|
||||
* STATUS_SUCCESS or error code.
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchRegSetRecord(
|
||||
PWSTR ClassName,
|
||||
const FSP_LAUNCH_REG_RECORD *Record);
|
||||
/**
|
||||
* Get a service registry record.
|
||||
*
|
||||
* @param ClassName
|
||||
* The service class name.
|
||||
* @param Agent
|
||||
* The name of the agent that is retrieving the service record. This API matches
|
||||
* the supplied Agent against the Agent in the service record and it only returns
|
||||
* the record if they match. Pass NULL to match any Agent.
|
||||
* @param PRecord
|
||||
* Pointer to a record pointer. Memory for the service record will be allocated
|
||||
* and a pointer to it will be stored at this address. This memory must be later
|
||||
* freed using FspLaunchRegFreeRecord.
|
||||
* @return
|
||||
* STATUS_SUCCESS or error code.
|
||||
* @see
|
||||
* FspLaunchRegFreeRecord
|
||||
*/
|
||||
FSP_API NTSTATUS FspLaunchRegGetRecord(
|
||||
PWSTR ClassName, PWSTR Agent,
|
||||
FSP_LAUNCH_REG_RECORD **PRecord);
|
||||
/**
|
||||
* Free a service registry record.
|
||||
*
|
||||
* @param Record
|
||||
* The service record to free.
|
||||
* @see
|
||||
* FspLaunchRegGetRecord
|
||||
*/
|
||||
FSP_API VOID FspLaunchRegFreeRecord(
|
||||
FSP_LAUNCH_REG_RECORD *Record);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
2240
support/3rd_party/winfsp-2.0/inc/winfsp/winfsp.h
vendored
Normal file
2240
support/3rd_party/winfsp-2.0/inc/winfsp/winfsp.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
902
support/3rd_party/winfsp-2.0/inc/winfsp/winfsp.hpp
vendored
Normal file
902
support/3rd_party/winfsp-2.0/inc/winfsp/winfsp.hpp
vendored
Normal file
@ -0,0 +1,902 @@
|
||||
/**
|
||||
* @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
|
Reference in New Issue
Block a user