/** * @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 #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