mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-29 19:18:39 -05:00 
			
		
		
		
	inc,sys,tst: FSP_FSCTL_VOLUME_PARAMS: fine-grained timeouts
This commit is contained in:
		| @@ -124,44 +124,64 @@ enum | ||||
|     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;             /* 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/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;        /* unimplemented; set to 0 */\ | ||||
|     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 KmReservedFlags:1;\ | ||||
|     /* user-mode flags */\ | ||||
|     UINT32 UmFileContextIsUserContext2:1;   /* user mode: FileContext parameter is UserContext2 */\ | ||||
|     UINT32 UmFileContextIsFullContext:1;    /* user mode: FileContext parameter is FullContext */\ | ||||
|     UINT32 UmReservedFlags:14;\ | ||||
|     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 KmAdditionalReservedFlags:28;\ | ||||
|     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 Reserved32[3];\ | ||||
|     UINT64 Reserved64[2]; | ||||
| typedef struct | ||||
| { | ||||
|     UINT16 Version;                     /* set to 0 */ | ||||
|     /* 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;             /* 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/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;        /* unimplemented; set to 0 */ | ||||
|     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 KmReservedFlags:1; | ||||
|     /* user-mode flags */ | ||||
|     UINT32 UmFileContextIsUserContext2:1;   /* user mode: FileContext parameter is UserContext2 */ | ||||
|     UINT32 UmFileContextIsFullContext:1;    /* user mode: FileContext parameter is FullContext */ | ||||
|     UINT32 UmReservedFlags:14; | ||||
|     WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */ | ||||
|     WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)]; | ||||
|     FSP_FSCTL_VOLUME_PARAMS_V0_FIELD_DEFN | ||||
| } FSP_FSCTL_VOLUME_PARAMS_V0; | ||||
| typedef struct | ||||
| { | ||||
|     FSP_FSCTL_VOLUME_PARAMS_V0_FIELD_DEFN | ||||
|     FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN | ||||
| } FSP_FSCTL_VOLUME_PARAMS; | ||||
| typedef struct | ||||
| { | ||||
|   | ||||
| @@ -31,7 +31,7 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath, | ||||
| { | ||||
|     NTSTATUS Result; | ||||
|     PWSTR DeviceRoot; | ||||
|     SIZE_T DeviceRootSize, DevicePathSize; | ||||
|     SIZE_T DeviceRootSize, DevicePathSize, VolumeParamsSize; | ||||
|     WCHAR DevicePathBuf[MAX_PATH + sizeof *VolumeParams], *DevicePathPtr, *DevicePathEnd; | ||||
|     HANDLE VolumeHandle = INVALID_HANDLE_VALUE; | ||||
|     DWORD Bytes; | ||||
| @@ -55,8 +55,11 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath, | ||||
|     memcpy(DevicePathPtr, DevicePath, DevicePathSize); | ||||
|     DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + DevicePathSize); | ||||
|     memcpy(DevicePathPtr, PREFIXW, PREFIXW_SIZE); | ||||
|     VolumeParamsSize = 0 == VolumeParams->Version ? | ||||
|         sizeof(FSP_FSCTL_VOLUME_PARAMS_V0) : | ||||
|         VolumeParams->Version; | ||||
|     DevicePathPtr = (PVOID)((PUINT8)DevicePathPtr + PREFIXW_SIZE); | ||||
|     DevicePathEnd = (PVOID)((PUINT8)DevicePathPtr + sizeof *VolumeParams * sizeof(WCHAR)); | ||||
|     DevicePathEnd = (PVOID)((PUINT8)DevicePathPtr + VolumeParamsSize * sizeof(WCHAR)); | ||||
|     for (PUINT8 VolumeParamsPtr = (PVOID)VolumeParams; | ||||
|         DevicePathEnd > DevicePathPtr; DevicePathPtr++, VolumeParamsPtr++) | ||||
|     { | ||||
|   | ||||
| @@ -346,7 +346,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) | ||||
|     FsvolDeviceExtension->InitDoneIoq = 1; | ||||
|  | ||||
|     /* create our security meta cache */ | ||||
|     SecurityTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout); | ||||
|     SecurityTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.SecurityTimeout); | ||||
|         /* convert millis to nanos */ | ||||
|     Result = FspMetaCacheCreate( | ||||
|         FspFsvolDeviceSecurityCacheCapacity, FspFsvolDeviceSecurityCacheItemSizeMax, &SecurityTimeout, | ||||
| @@ -356,7 +356,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) | ||||
|     FsvolDeviceExtension->InitDoneSec = 1; | ||||
|  | ||||
|     /* create our directory meta cache */ | ||||
|     DirInfoTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout); | ||||
|     DirInfoTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.DirInfoTimeout); | ||||
|         /* convert millis to nanos */ | ||||
|     Result = FspMetaCacheCreate( | ||||
|         FspFsvolDeviceDirInfoCacheCapacity, FspFsvolDeviceDirInfoCacheItemSizeMax, &DirInfoTimeout, | ||||
| @@ -366,7 +366,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject) | ||||
|     FsvolDeviceExtension->InitDoneDir = 1; | ||||
|  | ||||
|     /* create our stream info meta cache */ | ||||
|     StreamInfoTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.FileInfoTimeout); | ||||
|     StreamInfoTimeout.QuadPart = FspTimeoutFromMillis(FsvolDeviceExtension->VolumeParams.StreamInfoTimeout); | ||||
|         /* convert millis to nanos */ | ||||
|     Result = FspMetaCacheCreate( | ||||
|         FspFsvolDeviceStreamInfoCacheCapacity, FspFsvolDeviceStreamInfoCacheItemSizeMax, &StreamInfoTimeout, | ||||
| @@ -873,7 +873,7 @@ VOID FspFsvolDeviceSetVolumeInfo(PDEVICE_OBJECT DeviceObject, const FSP_FSCTL_VO | ||||
|     KeAcquireSpinLock(&FsvolDeviceExtension->InfoSpinLock, &Irql); | ||||
|     FsvolDeviceExtension->VolumeInfo = VolumeInfoNp; | ||||
|     FsvolDeviceExtension->InfoExpirationTime = FspExpirationTimeFromMillis( | ||||
|         FsvolDeviceExtension->VolumeParams.FileInfoTimeout); | ||||
|         FsvolDeviceExtension->VolumeParams.VolumeInfoTimeout); | ||||
|     KeReleaseSpinLock(&FsvolDeviceExtension->InfoSpinLock, Irql); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -551,7 +551,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry( | ||||
|         FsvolDeviceExtension->VolumeParams.MaxComponentLength * sizeof(WCHAR); | ||||
|     QueryDirectoryLengthMin = FSP_FSCTL_ALIGN_UP(QueryDirectoryLengthMin, 8); | ||||
|     ASSERT(QueryDirectoryLengthMin < FspFsvolQueryDirectoryLengthMax); | ||||
|     if (0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && | ||||
|     if (0 != FsvolDeviceExtension->VolumeParams.DirInfoTimeout && | ||||
|         0 == FileDesc->DirectoryMarker.Buffer) | ||||
|     { | ||||
|         if (PatternIsFileName) | ||||
|   | ||||
| @@ -101,18 +101,26 @@ static NTSTATUS FspVolumeCreateNoLock( | ||||
|     FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension; | ||||
|  | ||||
|     /* check parameters */ | ||||
|     if (PREFIXW_SIZE + sizeof(FSP_FSCTL_VOLUME_PARAMS) * sizeof(WCHAR) > FileObject->FileName.Length) | ||||
|     if (PREFIXW_SIZE + sizeof(FSP_FSCTL_VOLUME_PARAMS_V0) * sizeof(WCHAR) > FileObject->FileName.Length) | ||||
|         return STATUS_INVALID_PARAMETER; | ||||
|  | ||||
|     /* copy the VolumeParams */ | ||||
|     for (USHORT Index = 0, Length = sizeof(FSP_FSCTL_VOLUME_PARAMS); Length > Index; Index++) | ||||
|     { | ||||
|         if (PREFIXW_SIZE / sizeof(WCHAR) + Index >= FileObject->FileName.Length / sizeof(WCHAR)) | ||||
|             break; | ||||
|  | ||||
|         WCHAR Value = FileObject->FileName.Buffer[PREFIXW_SIZE / sizeof(WCHAR) + Index]; | ||||
|         if (0xF000 != (Value & 0xFF00)) | ||||
|             return STATUS_INVALID_PARAMETER; | ||||
|         ((PUINT8)&VolumeParams)[Index] = Value & 0xFF; | ||||
|     } | ||||
|  | ||||
|     /* check VolumeParams size */ | ||||
|     if (0 != VolumeParams.Version && | ||||
|         PREFIXW_SIZE + VolumeParams.Version * sizeof(WCHAR) != FileObject->FileName.Length) | ||||
|         return STATUS_INVALID_PARAMETER; | ||||
|  | ||||
|     /* check the VolumeParams */ | ||||
|     if (0 == VolumeParams.SectorSize) | ||||
|         VolumeParams.SectorSize = 512; | ||||
| @@ -133,6 +141,28 @@ static NTSTATUS FspVolumeCreateNoLock( | ||||
|     if (FspFsctlIrpCapacityMinimum > VolumeParams.IrpCapacity || | ||||
|         VolumeParams.IrpCapacity > FspFsctlIrpCapacityMaximum) | ||||
|         VolumeParams.IrpCapacity = FspFsctlIrpCapacityDefault; | ||||
|     if (sizeof(FSP_FSCTL_VOLUME_PARAMS_V0) >= VolumeParams.Version) | ||||
|     { | ||||
|         VolumeParams.VolumeInfoTimeout = VolumeParams.FileInfoTimeout; | ||||
|         VolumeParams.DirInfoTimeout = VolumeParams.FileInfoTimeout; | ||||
|         VolumeParams.SecurityTimeout = VolumeParams.FileInfoTimeout; | ||||
|         VolumeParams.StreamInfoTimeout = VolumeParams.FileInfoTimeout; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if (!VolumeParams.VolumeInfoTimeoutValid) | ||||
|             VolumeParams.VolumeInfoTimeout = VolumeParams.FileInfoTimeout; | ||||
|         if (!VolumeParams.DirInfoTimeoutValid) | ||||
|             VolumeParams.DirInfoTimeout = VolumeParams.FileInfoTimeout; | ||||
|         if (!VolumeParams.SecurityTimeoutValid) | ||||
|             VolumeParams.SecurityTimeout = VolumeParams.FileInfoTimeout; | ||||
|         if (!VolumeParams.StreamInfoTimeoutValid) | ||||
|             VolumeParams.StreamInfoTimeout = VolumeParams.FileInfoTimeout; | ||||
|     } | ||||
|     VolumeParams.VolumeInfoTimeoutValid = 1; | ||||
|     VolumeParams.DirInfoTimeoutValid = 1; | ||||
|     VolumeParams.SecurityTimeoutValid = 1; | ||||
|     VolumeParams.StreamInfoTimeoutValid = 1; | ||||
|     if (FILE_DEVICE_NETWORK_FILE_SYSTEM == FsctlDeviceObject->DeviceType) | ||||
|     { | ||||
|         VolumeParams.Prefix[sizeof VolumeParams.Prefix / sizeof(WCHAR) - 1] = L'\0'; | ||||
|   | ||||
| @@ -2008,6 +2008,7 @@ NTSTATUS MemfsCreateFunnel( | ||||
|     } | ||||
|  | ||||
|     memset(&VolumeParams, 0, sizeof VolumeParams); | ||||
|     VolumeParams.Version = sizeof FSP_FSCTL_VOLUME_PARAMS; | ||||
|     VolumeParams.SectorSize = MEMFS_SECTOR_SIZE; | ||||
|     VolumeParams.SectorsPerAllocationUnit = MEMFS_SECTORS_PER_ALLOCATION_UNIT; | ||||
|     VolumeParams.VolumeCreationTime = MemfsGetSystemTime(); | ||||
|   | ||||
| @@ -61,11 +61,40 @@ void mount_open_device_test(void) | ||||
|         mount_open_device_dotest(L"WinFsp.Net"); | ||||
| } | ||||
|  | ||||
| void mount_create_volume_v0_dotest(PWSTR DeviceName) | ||||
| { | ||||
|     NTSTATUS Result; | ||||
|     BOOL Success; | ||||
|     FSP_FSCTL_VOLUME_PARAMS_V0 VolumeParams = { 0 }; | ||||
|     WCHAR VolumeName[MAX_PATH]; | ||||
|     HANDLE VolumeHandle; | ||||
|  | ||||
|     VolumeParams.SectorSize = 16384; | ||||
|     VolumeParams.VolumeSerialNumber = 0x12345678; | ||||
|     wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), L"\\winfsp-tests\\share"); | ||||
|     Result = FspFsctlCreateVolume(DeviceName, (FSP_FSCTL_VOLUME_PARAMS *)&VolumeParams, | ||||
|         VolumeName, sizeof VolumeName, &VolumeHandle); | ||||
|     ASSERT(STATUS_SUCCESS == Result); | ||||
|     ASSERT(0 == wcsncmp(L"\\Device\\Volume{", VolumeName, 15)); | ||||
|     ASSERT(INVALID_HANDLE_VALUE != VolumeHandle); | ||||
|  | ||||
|     Success = CloseHandle(VolumeHandle); | ||||
|     ASSERT(Success); | ||||
| } | ||||
|  | ||||
| void mount_create_volume_v0_test(void) | ||||
| { | ||||
|     if (WinFspDiskTests) | ||||
|         mount_create_volume_v0_dotest(L"WinFsp.Disk"); | ||||
|     if (WinFspNetTests) | ||||
|         mount_create_volume_v0_dotest(L"WinFsp.Net"); | ||||
| } | ||||
|  | ||||
| void mount_create_volume_dotest(PWSTR DeviceName) | ||||
| { | ||||
|     NTSTATUS Result; | ||||
|     BOOL Success; | ||||
|     FSP_FSCTL_VOLUME_PARAMS VolumeParams = { 0 }; | ||||
|     FSP_FSCTL_VOLUME_PARAMS VolumeParams = { .Version = sizeof VolumeParams }; | ||||
|     WCHAR VolumeName[MAX_PATH]; | ||||
|     HANDLE VolumeHandle; | ||||
|  | ||||
| @@ -341,6 +370,7 @@ void mount_tests(void) | ||||
|  | ||||
|     TEST_OPT(mount_invalid_test); | ||||
|     TEST_OPT(mount_open_device_test); | ||||
|     TEST_OPT(mount_create_volume_v0_test); | ||||
|     TEST_OPT(mount_create_volume_test); | ||||
|     TEST_OPT(mount_volume_cancel_test); | ||||
|     TEST_OPT(mount_volume_transact_test); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user