From 1c464cad2b6d5c452c3a07e4a22e905b6ef137e2 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 25 Jan 2016 12:02:52 -0800 Subject: [PATCH] fsctl: FSP_FSCTL_VOLUME_PARAMS --- inc/winfsp/fsctl.h | 40 ++++++++++++++++++++------- src/sys/device.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++ src/sys/driver.h | 9 ++++++- src/sys/volinfo.c | 24 ++++++++++------- src/sys/volume.c | 4 +++ 5 files changed, 124 insertions(+), 20 deletions(-) diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 433fe6f4..8bdfd4bc 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -43,7 +43,14 @@ extern const __declspec(selectany) GUID FspFsvrtDeviceClassGuid = #define FSP_FSCTL_TRANSACT_REQ_SIZEMAX (4096 - 64) /* 64: size for internal request header */ #define FSP_FSCTL_TRANSACT_RSP_SIZEMAX (4096 - 64) /* symmetry! */ -/* file metadata */ +/* volume/file metadata */ +typedef struct +{ + UINT64 TotalAllocationUnits; + UINT64 AvailableAllocationUnits; + UINT16 VolumeLabelLength; + WCHAR VolumeLabel[32]; +} FSP_FSCTL_VOLUME_INFO; typedef struct { UINT32 FileAttributes; @@ -100,14 +107,28 @@ enum }; typedef struct { - UINT16 Version; + UINT16 Version; /* set to 0 */ + /* volume information */ UINT16 SectorSize; - UINT32 SerialNumber; - UINT32 TransactTimeout; /* milliseconds; values between 1 sec and 10 sec */ - UINT32 IrpTimeout; /* milliseconds; values between 1 min and 10 min */ - UINT32 IrpCapacity; /* maximum number of pending IRP's */ - UINT32 FileInfoTimeout; /* milliseconds */ - UINT32 EaSupported:1; /* supports extended attributes (unimplemented; set to 0) */ + UINT16 SectorsPerAllocationUnit; + UINT16 MaxComponentLength; /* maximum file name component length (bytes) */ + UINT32 SerialNumber; /* volume serial number */ + /* I/O timeouts, capacity, etc. */ + UINT32 TransactTimeout; /* FSP_FSCTL_TRANSACT timeout (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/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 (!!!: unimplemented) */ + UINT32 NamedStreams:1; /* file system supports named streams (!!!: unimplemented) */ + UINT32 HardLinks:1; /* unimplemented; set to 0 */ + UINT32 ExtendedAttributes:1; /* unimplemented; set to 0 */ + UINT32 ReadOnlyVolume:1; + /* other flags */ UINT32 FileNameRequired:1; /* FileName required for all operations (not just Create) */ WCHAR Prefix[64]; /* UNC prefix to recognize (\\server\path format, 0-term) */ } FSP_FSCTL_VOLUME_PARAMS; @@ -205,8 +226,7 @@ typedef struct } QueryInformation; struct { - UINT64 TotalAllocationUnits; - UINT64 AvailableAllocationUnits; + FSP_FSCTL_VOLUME_INFO VolumeInfo; } QueryVolumeInformation; } Rsp; FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[]; diff --git a/src/sys/device.c b/src/sys/device.c index 4e639f94..86c4e031 100644 --- a/src/sys/device.c +++ b/src/sys/device.c @@ -35,6 +35,9 @@ VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, static RTL_AVL_COMPARE_ROUTINE FspFsvolDeviceCompareElement; static RTL_AVL_ALLOCATE_ROUTINE FspFsvolDeviceAllocateElement; static RTL_AVL_FREE_ROUTINE FspFsvolDeviceFreeElement; +VOID FspFsvolGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo); +BOOLEAN FspFsvolTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo); +VOID FspFsvolSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo); NTSTATUS FspDeviceCopyList( PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount); VOID FspDeviceDeleteList( @@ -307,6 +310,10 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) IoStartTimer(DeviceObject); FsvolDeviceExtension->InitDoneTimer = 1; + /* initialize the volume information */ + KeInitializeSpinLock(&FsvolDeviceExtension->InfoSpinLock); + FsvolDeviceExtension->InitDoneInfo = 1; + return STATUS_SUCCESS; } @@ -509,6 +516,66 @@ static VOID NTAPI FspFsvolDeviceFreeElement( PAGED_CODE(); } +VOID FspFsvolGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo) +{ + // !PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + FSP_FSCTL_VOLUME_INFO VolumeInfoNp; + KIRQL Irql; + + KeAcquireSpinLock(&FsvolDeviceExtension->InfoSpinLock, &Irql); + VolumeInfoNp = FsvolDeviceExtension->VolumeInfo; + KeReleaseSpinLock(&FsvolDeviceExtension->InfoSpinLock, Irql); + + *VolumeInfo = VolumeInfoNp; +} + +#pragma warning(push) +#pragma warning(disable:4701) /* disable idiotic warning! */ +BOOLEAN FspFsvolTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo) +{ + // !PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + FSP_FSCTL_VOLUME_INFO VolumeInfoNp; + KIRQL Irql; + BOOLEAN Result; + + KeAcquireSpinLock(&FsvolDeviceExtension->InfoSpinLock, &Irql); + if (0 < FsvolDeviceExtension->InfoExpirationTime && + KeQueryInterruptTime() < FsvolDeviceExtension->InfoExpirationTime) + { + VolumeInfoNp = FsvolDeviceExtension->VolumeInfo; + Result = TRUE; + } + else + Result = FALSE; + KeReleaseSpinLock(&FsvolDeviceExtension->InfoSpinLock, Irql); + + if (Result) + *VolumeInfo = VolumeInfoNp; + + return Result; +} +#pragma warning(pop) + +VOID FspFsvolSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo) +{ + // !PAGED_CODE(); + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject); + FSP_FSCTL_VOLUME_INFO VolumeInfoNp = *VolumeInfo; + KIRQL Irql; + UINT64 FileInfoTimeout = FsvolDeviceExtension->VolumeParams.FileInfoTimeout * 10000ULL; + + KeAcquireSpinLock(&FsvolDeviceExtension->InfoSpinLock, &Irql); + FsvolDeviceExtension->VolumeInfo = VolumeInfoNp; + FsvolDeviceExtension->InfoExpirationTime = 0 != FileInfoTimeout ? + KeQueryInterruptTime() + FileInfoTimeout : 0; + KeReleaseSpinLock(&FsvolDeviceExtension->InfoSpinLock, Irql); +} + NTSTATUS FspDeviceCopyList( PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount) { diff --git a/src/sys/driver.h b/src/sys/driver.h index 1e0aed55..44505db8 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -443,7 +443,8 @@ typedef struct typedef struct { FSP_DEVICE_EXTENSION Base; - UINT32 InitDoneFsvrt:1, InitDoneDelRsc:1, InitDoneIoq:1, InitDoneGenTab:1, InitDoneTimer:1; + UINT32 InitDoneFsvrt:1, InitDoneDelRsc:1, InitDoneIoq:1, InitDoneGenTab:1, InitDoneTimer:1, + InitDoneInfo:1; PDEVICE_OBJECT FsctlDeviceObject; PDEVICE_OBJECT FsvrtDeviceObject; HANDLE MupHandle; @@ -461,6 +462,9 @@ typedef struct PVOID GenericTableElementStorage; UNICODE_STRING VolumeName; WCHAR VolumeNameBuf[FSP_DEVICE_VOLUME_NAME_LENMAX / sizeof(WCHAR)]; + KSPIN_LOCK InfoSpinLock; + UINT64 InfoExpirationTime; + FSP_FSCTL_VOLUME_INFO VolumeInfo; } FSP_FSVOL_DEVICE_EXTENSION; static inline FSP_DEVICE_EXTENSION *FspDeviceExtension(PDEVICE_OBJECT DeviceObject) @@ -491,6 +495,9 @@ PVOID FspFsvolDeviceInsertContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier FSP_DEVICE_GENERIC_TABLE_ELEMENT *ElementStorage, PBOOLEAN PInserted); VOID FspFsvolDeviceDeleteContext(PDEVICE_OBJECT DeviceObject, UINT64 Identifier, PBOOLEAN PDeleted); +VOID FspFsvolGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo); +BOOLEAN FspFsvolTryGetVolumeInfo(PDEVICE_OBJECT DeviceObject, FSP_FSCTL_VOLUME_INFO *VolumeInfo); +VOID FspFsvolSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VOLUME_INFO *VolumeInfo); NTSTATUS FspDeviceCopyList( PDEVICE_OBJECT **PDeviceObjects, PULONG PDeviceObjectCount); VOID FspDeviceDeleteList( diff --git a/src/sys/volinfo.c b/src/sys/volinfo.c index ddb0a2ae..dd80a85f 100644 --- a/src/sys/volinfo.c +++ b/src/sys/volinfo.c @@ -12,12 +12,13 @@ static NTSTATUS FspFsvolQueryVolumeDeviceInformation( PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd); static NTSTATUS FspFsvolQueryVolumeFullSizeInformation( PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, - const UINT64 *Sizes); + const FSP_FSCTL_VOLUME_INFO *VolumeInfo); static NTSTATUS FspFsvolQueryVolumeSizeInformation( PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, - const UINT64 *Sizes); + const FSP_FSCTL_VOLUME_INFO *VolumeInfo); static NTSTATUS FspFsvolQueryVolumeFsVolumeInformation( - PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd); + PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, + const FSP_FSCTL_VOLUME_INFO *VolumeInfo); static NTSTATUS FspFsvolQueryVolumeInformation( PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); FSP_IOCMPL_DISPATCH FspFsvolQueryVolumeInformationComplete; @@ -59,7 +60,7 @@ static NTSTATUS FspFsvolQueryVolumeDeviceInformation( static NTSTATUS FspFsvolQueryVolumeFullSizeInformation( PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, - const UINT64 *Sizes) + const FSP_FSCTL_VOLUME_INFO *VolumeInfo) { PAGED_CODE(); @@ -68,7 +69,7 @@ static NTSTATUS FspFsvolQueryVolumeFullSizeInformation( static NTSTATUS FspFsvolQueryVolumeSizeInformation( PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, - const UINT64 *Sizes) + const FSP_FSCTL_VOLUME_INFO *VolumeInfo) { PAGED_CODE(); @@ -76,7 +77,8 @@ static NTSTATUS FspFsvolQueryVolumeSizeInformation( } static NTSTATUS FspFsvolQueryVolumeFsVolumeInformation( - PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd) + PDEVICE_OBJECT FsvolDeviceObject, PUINT8 *PBuffer, PUINT8 BufferEnd, + const FSP_FSCTL_VOLUME_INFO *VolumeInfo) { PAGED_CODE(); @@ -107,7 +109,7 @@ static NTSTATUS FspFsvolQueryVolumeInformation( Result = FspFsvolQueryVolumeSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0); break; case FileFsVolumeInformation: - Result = FspFsvolQueryVolumeFsVolumeInformation(FsvolDeviceObject, &Buffer, BufferEnd); + Result = FspFsvolQueryVolumeFsVolumeInformation(FsvolDeviceObject, &Buffer, BufferEnd, 0); break; default: Result = STATUS_INVALID_PARAMETER; @@ -158,11 +160,15 @@ VOID FspFsvolQueryVolumeInformationComplete( { case FileFsFullSizeInformation: Result = FspFsvolQueryVolumeFullSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, - &Response->Rsp.QueryVolumeInformation.TotalAllocationUnits); + &Response->Rsp.QueryVolumeInformation.VolumeInfo); break; case FileFsSizeInformation: Result = FspFsvolQueryVolumeSizeInformation(FsvolDeviceObject, &Buffer, BufferEnd, - &Response->Rsp.QueryVolumeInformation.TotalAllocationUnits); + &Response->Rsp.QueryVolumeInformation.VolumeInfo); + break; + case FileFsVolumeInformation: + Result = FspFsvolQueryVolumeFsVolumeInformation(FsvolDeviceObject, &Buffer, BufferEnd, + &Response->Rsp.QueryVolumeInformation.VolumeInfo); break; default: ASSERT(0); diff --git a/src/sys/volume.c b/src/sys/volume.c index cbb969a7..94686d17 100644 --- a/src/sys/volume.c +++ b/src/sys/volume.c @@ -87,6 +87,10 @@ NTSTATUS FspVolumeCreate( /* check the VolumeParams */ if (0 == VolumeParams.SectorSize) VolumeParams.SectorSize = 512; + if (0 == VolumeParams.SectorsPerAllocationUnit) + VolumeParams.SectorsPerAllocationUnit = 1; + if (0 == VolumeParams.MaxComponentLength) + VolumeParams.MaxComponentLength = 255; if (FspFsctlTransactTimeoutMinimum > VolumeParams.TransactTimeout || VolumeParams.TransactTimeout > FspFsctlTransactTimeoutMaximum) VolumeParams.TransactTimeout = FspFsctlTransactTimeoutDefault;