mirror of
https://github.com/winfsp/winfsp.git
synced 2025-07-03 01:12:58 -05:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
5a67c47d0f | |||
39c189aff7 | |||
3d9fc467ef | |||
23b5c67913 | |||
4b5478e50c | |||
c7fc728ad0 | |||
254174b8e9 | |||
5110b3c5a1 |
@ -1,6 +1,42 @@
|
|||||||
= Changelog
|
= Changelog
|
||||||
|
|
||||||
|
|
||||||
|
v1.5B4 (2019.3 B4)::
|
||||||
|
|
||||||
|
Changes since v1.4:
|
||||||
|
|
||||||
|
* [GEN] WinFsp file systems can now be used by WSLinux. File systems must enable this support by setting the `FSP_FSCTL_VOLUME_PARAMS::WslFeatures` bit. Use the command `sudo mount -t drvfs x: /mnt/x` to mount.
|
||||||
|
* [GEN] Extended attribute support has been added for all WinFsp API's: native, .NET, FUSE2 and FUSE3.
|
||||||
|
* [GEN] Mount Manager support has been added and it works for current and new file systems:
|
||||||
|
** If the file system mountpoint is in the syntax `\\.\X:` then the Mount Manager is used.
|
||||||
|
** If the file system mountpoint is in the syntax `X:` then `DefineDosDeviceW` is used (i.e. same as today).
|
||||||
|
** If the file system mountpoint is in the syntax `X:\DIR` then a reparse point is used and the file system is mounted as a directory (i.e. same as today).
|
||||||
|
** Caveats:
|
||||||
|
*** It requires Administrator access. This is because opening the `\\.\MountPointManager` device requires Administrator access.
|
||||||
|
*** It currently works with drives (`\\.\X:`) but not directories (`\\.\X:\DIR`).
|
||||||
|
*** Mount Manager drives created by WinFsp are transient. WinFsp takes various steps to ensure that this is the case.
|
||||||
|
*** Mount Manager drives are global and are visible across Terminal Services sessions (they go into the `\GLOBAL??` portion of the NT namespace).
|
||||||
|
* [FSD] Support for kernel-mode file systems on top of WinFsp has been added. See `FspFsextProvider`. This is in preparation for WinFuse - FUSE for Windows and WSLinux.
|
||||||
|
* [FSD] FastIO support has been added. FastIO operations are enabled on cache-enabled file systems with the notable exception of `FastIoQueryOpen`, which allows opening files in kernel mode; this operation requires the file system to specify the `FSP_FSCTL_VOLUME_PARAMS::AllowOpenInKernelMode` flag.
|
||||||
|
* [FSD] Support for `FileFsSectorSizeInformation` and `IOCTL_STORAGE_QUERY_PROPERTY / StorageAccessAlignmentProperty` has been added.
|
||||||
|
* [DLL] The `FspFileSystemStartDispatcher` default number of threads (`ThreadCount==0`) has been changed. See commit 3902874ac93fe40685d9761f46a96358ba24f24c for more.
|
||||||
|
* [FUSE] FUSE has new `-o UserName=DOMAIN+USERNAME` and `-o GroupName=DOMAIN+GROUPNAME` options. These function like the `-o uid=UID` and `-o gid=GID` options, but accept Windows user and groups names.
|
||||||
|
* [FUSE] FUSE has new `-o dothidden` option that is used to add the Windows hidden file attribute to files that start with a dot.
|
||||||
|
* [FUSE] FUSE has new `-o create_file_umask=nnn` and `-o create_dir_umask=nnn` options that allow for more control than the `-o create_umask=nnn` option.
|
||||||
|
* [FUSE] FUSE has new `--ExactFileSystemName=FSNAME` option that removes the "FUSE-" prefix from the file system name. (Use with caution: see discussion in PR #251.) (Thanks @johntyner.)
|
||||||
|
* [.NET] The .NET API now supports asynchronous handling of `Read`, `Write` and `ReadDirectory`. (Thanks @dworkin.)
|
||||||
|
* [.NET] The .NET API now supports fine-grained timeouts (`VolumeInfoTimeout`, `DirInfoTimeout`, etc).
|
||||||
|
* [.NET] The .NET API has new method `FileSystemHost.MountEx` that adds a `ThreadCount` parameter.
|
||||||
|
* [LAUNCH] The Launcher can now rewrite path arguments passed to file systems during launching using "Path Transformation Language". See commit a73f1b95592617ac7484e16c2e642573a4d65644 for more.
|
||||||
|
* [MEMFS] A new memfs FUSE3 file system written in C++ has been added. See `tst/memfs-fuse3`.
|
||||||
|
* [AIRFS] John Oberschelp has done some fantastic work adding persistence to the airfs file system. (Thanks @JohnOberschelp.)
|
||||||
|
* [FIX] Fixes for very large (> 4GiB) files. (Thanks @dworkin.)
|
||||||
|
* [FIX] A fix for how FUSE handles the return value from `opendir`. (GitHub issue billziss-gh/sshfs-win#54)
|
||||||
|
* [FIX] A fix for an invalid UID to SID mapping on domains with a lot of users. (Thanks @sganis.)
|
||||||
|
* [FIX] A fix on the C++ layer. (Thanks @colatkinson.)
|
||||||
|
* Other fixes and improvements.
|
||||||
|
|
||||||
|
|
||||||
v1.5B3 (2019.3 B3)::
|
v1.5B3 (2019.3 B3)::
|
||||||
|
|
||||||
Changes since v1.4:
|
Changes since v1.4:
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<MyCanonicalVersion>1.5</MyCanonicalVersion>
|
<MyCanonicalVersion>1.5</MyCanonicalVersion>
|
||||||
|
|
||||||
<MyProductVersion>2019.3 B3</MyProductVersion>
|
<MyProductVersion>2019.3 B4</MyProductVersion>
|
||||||
<MyProductStage>Beta</MyProductStage>
|
<MyProductStage>Beta</MyProductStage>
|
||||||
|
|
||||||
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
|
||||||
|
@ -96,7 +96,7 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR),
|
|||||||
|
|
||||||
/* marshalling */
|
/* marshalling */
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable:4200) /* zero-sized array in struct/union */
|
#pragma warning(disable:4200 4201) /* zero-sized array in struct/union; nameless struct/union */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FspFsctlTransactReservedKind = 0,
|
FspFsctlTransactReservedKind = 0,
|
||||||
@ -175,7 +175,8 @@ enum
|
|||||||
UINT32 AllowOpenInKernelMode:1; /* allow kernel mode to open files when possible */\
|
UINT32 AllowOpenInKernelMode:1; /* allow kernel mode to open files when possible */\
|
||||||
UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\
|
UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\
|
||||||
UINT32 WslFeatures:1; /* support features required for WSLinux */\
|
UINT32 WslFeatures:1; /* support features required for WSLinux */\
|
||||||
UINT32 KmReservedFlags:5;\
|
UINT32 DirectoryMarkerAsNextOffset:1; /* directory marker is next offset instead of last name */\
|
||||||
|
UINT32 KmReservedFlags:4;\
|
||||||
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\
|
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\
|
||||||
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
|
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
|
||||||
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\
|
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\
|
||||||
@ -242,8 +243,12 @@ typedef struct
|
|||||||
{
|
{
|
||||||
UINT16 Size;
|
UINT16 Size;
|
||||||
FSP_FSCTL_FILE_INFO FileInfo;
|
FSP_FSCTL_FILE_INFO FileInfo;
|
||||||
UINT8 Padding[24];
|
union
|
||||||
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */
|
{
|
||||||
|
UINT64 NextOffset;
|
||||||
|
UINT8 Padding[24];
|
||||||
|
/* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */
|
||||||
|
} DUMMYUNIONNAME;
|
||||||
WCHAR FileNameBuf[];
|
WCHAR FileNameBuf[];
|
||||||
} FSP_FSCTL_DIR_INFO;
|
} FSP_FSCTL_DIR_INFO;
|
||||||
FSP_FSCTL_STATIC_ASSERT(104 == sizeof(FSP_FSCTL_DIR_INFO),
|
FSP_FSCTL_STATIC_ASSERT(104 == sizeof(FSP_FSCTL_DIR_INFO),
|
||||||
|
@ -53,6 +53,9 @@ typedef struct
|
|||||||
|
|
||||||
FSP_DDI_DEF(NTSTATUS, FspFsextProviderRegister,
|
FSP_DDI_DEF(NTSTATUS, FspFsextProviderRegister,
|
||||||
FSP_FSEXT_PROVIDER *Provider)
|
FSP_FSEXT_PROVIDER *Provider)
|
||||||
|
FSP_DDI_DEF(NTSTATUS, FspFsextProviderTransact,
|
||||||
|
PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
||||||
|
FSP_FSCTL_TRANSACT_RSP *Response, FSP_FSCTL_TRANSACT_REQ **PRequest)
|
||||||
|
|
||||||
FSP_DDI_DEF(NTSTATUS, FspPosixMapUidToSid,
|
FSP_DDI_DEF(NTSTATUS, FspPosixMapUidToSid,
|
||||||
UINT32 Uid,
|
UINT32 Uid,
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -72,7 +72,10 @@ NTSYSAPI VOID NTAPI RtlMoveMemory(VOID *Destination, CONST VOID *Source, DWORD L
|
|||||||
|
|
||||||
#pragma function(memset)
|
#pragma function(memset)
|
||||||
#pragma function(memcpy)
|
#pragma function(memcpy)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4163) /* not available as an intrinsic function */
|
||||||
#pragma function(memmove)
|
#pragma function(memmove)
|
||||||
|
#pragma warning(pop)
|
||||||
static inline
|
static inline
|
||||||
void *memset(void *dst, int val, size_t siz)
|
void *memset(void *dst, int val, size_t siz)
|
||||||
{
|
{
|
||||||
|
@ -340,6 +340,7 @@ static NTSTATUS FspFsvolDeviceInit(PDEVICE_OBJECT DeviceObject)
|
|||||||
Result = Provider->DeviceInit(DeviceObject, &FsvolDeviceExtension->VolumeParams);
|
Result = Provider->DeviceInit(DeviceObject, &FsvolDeviceExtension->VolumeParams);
|
||||||
if (!NT_SUCCESS(Result))
|
if (!NT_SUCCESS(Result))
|
||||||
return Result;
|
return Result;
|
||||||
|
FsvolDeviceExtension->Provider = Provider;
|
||||||
FsvolDeviceExtension->InitDoneFsext = 1;
|
FsvolDeviceExtension->InitDoneFsext = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -525,10 +526,8 @@ static VOID FspFsvolDeviceFini(PDEVICE_OBJECT DeviceObject)
|
|||||||
/* finalize any fsext provider */
|
/* finalize any fsext provider */
|
||||||
if (FsvolDeviceExtension->InitDoneFsext)
|
if (FsvolDeviceExtension->InitDoneFsext)
|
||||||
{
|
{
|
||||||
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
|
if (0 != FsvolDeviceExtension->Provider)
|
||||||
FsvolDeviceExtension->VolumeParams.FsextControlCode, 0);
|
FsvolDeviceExtension->Provider->DeviceFini(DeviceObject);
|
||||||
if (0 != Provider)
|
|
||||||
Provider->DeviceFini(DeviceObject);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,13 +576,8 @@ static VOID FspFsvolDeviceExpirationRoutine(PVOID Context)
|
|||||||
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime);
|
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->DirInfoCache, InterruptTime);
|
||||||
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime);
|
FspMetaCacheInvalidateExpired(FsvolDeviceExtension->StreamInfoCache, InterruptTime);
|
||||||
/* run any fsext provider expiration routine */
|
/* run any fsext provider expiration routine */
|
||||||
if (0 != FsvolDeviceExtension->VolumeParams.FsextControlCode)
|
if (0 != FsvolDeviceExtension->Provider)
|
||||||
{
|
FsvolDeviceExtension->Provider->DeviceExpirationRoutine(DeviceObject, InterruptTime);
|
||||||
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
|
|
||||||
FsvolDeviceExtension->VolumeParams.FsextControlCode, 0);
|
|
||||||
if (0 != Provider)
|
|
||||||
Provider->DeviceExpirationRoutine(DeviceObject, InterruptTime);
|
|
||||||
}
|
|
||||||
FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime);
|
FspIoqRemoveExpired(FsvolDeviceExtension->Ioq, InterruptTime);
|
||||||
|
|
||||||
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);
|
KeAcquireSpinLock(&FsvolDeviceExtension->ExpirationLock, &Irql);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||||
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
||||||
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
|
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
|
||||||
|
PUINT64 DirectoryMarkerAsNextOffset,
|
||||||
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
|
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
|
||||||
BOOLEAN ReturnEaSize,
|
BOOLEAN ReturnEaSize,
|
||||||
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
|
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
|
||||||
@ -88,6 +89,7 @@ enum
|
|||||||
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
static NTSTATUS FspFsvolQueryDirectoryCopy(
|
||||||
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive,
|
||||||
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
|
PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut,
|
||||||
|
PUINT64 DirectoryMarkerAsNextOffset,
|
||||||
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
|
FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry,
|
||||||
BOOLEAN ReturnEaSize,
|
BOOLEAN ReturnEaSize,
|
||||||
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
|
FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize,
|
||||||
@ -130,6 +132,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
PVOID PrevDestBuf = 0;
|
PVOID PrevDestBuf = 0;
|
||||||
ULONG BaseInfoLen, CopyLength;
|
ULONG BaseInfoLen, CopyLength;
|
||||||
UNICODE_STRING FileName;
|
UNICODE_STRING FileName;
|
||||||
|
UINT64 DirectoryNextOffset;
|
||||||
|
|
||||||
*PDestLen = 0;
|
*PDestLen = 0;
|
||||||
|
|
||||||
@ -176,12 +179,21 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO));
|
FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO));
|
||||||
FileName.Buffer = DirInfo->FileNameBuf;
|
FileName.Buffer = DirInfo->FileNameBuf;
|
||||||
|
|
||||||
|
DirectoryNextOffset = DirInfo->NextOffset;
|
||||||
|
|
||||||
if (0 != DirectoryMarker && 0 != DirectoryMarker->Buffer &&
|
if (0 != DirectoryMarker && 0 != DirectoryMarker->Buffer &&
|
||||||
!DirectoryMarkerFound)
|
!DirectoryMarkerFound)
|
||||||
{
|
{
|
||||||
DirectoryMarkerFound = 0 == FspFileNameCompare(
|
if (0 == DirectoryMarkerAsNextOffset)
|
||||||
&FileName, DirectoryMarker, CaseInsensitive, 0);
|
{
|
||||||
continue;
|
DirectoryMarkerFound = 0 == FspFileNameCompare(
|
||||||
|
&FileName, DirectoryMarker, CaseInsensitive, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT(sizeof(UINT64) == DirectoryMarker->Length);
|
||||||
|
DirectoryMarkerFound = DirectoryNextOffset == *(PUINT64)DirectoryMarker->Buffer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
|
/* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */
|
||||||
@ -272,8 +284,17 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = FileName.Length;
|
if (0 == DirectoryMarkerAsNextOffset)
|
||||||
DirectoryMarkerOut->Buffer = (PVOID)((PUINT8)DestBuf + BaseInfoLen);
|
{
|
||||||
|
DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = FileName.Length;
|
||||||
|
DirectoryMarkerOut->Buffer = (PVOID)((PUINT8)DestBuf + BaseInfoLen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = sizeof(UINT64);
|
||||||
|
DirectoryMarkerOut->Buffer = (PVOID)DirectoryMarkerAsNextOffset;
|
||||||
|
*DirectoryMarkerAsNextOffset = DirectoryNextOffset;
|
||||||
|
}
|
||||||
|
|
||||||
DestBuf = (PVOID)((PUINT8)DestBuf +
|
DestBuf = (PVOID)((PUINT8)DestBuf +
|
||||||
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
|
FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG)));
|
||||||
@ -283,7 +304,16 @@ static NTSTATUS FspFsvolQueryDirectoryCopy(
|
|||||||
Loop = FALSE;
|
Loop = FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*DirectoryMarkerOut = FileName;
|
{
|
||||||
|
if (0 == DirectoryMarkerAsNextOffset)
|
||||||
|
*DirectoryMarkerOut = FileName;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = sizeof(UINT64);
|
||||||
|
DirectoryMarkerOut->Buffer = (PVOID)DirectoryMarkerAsNextOffset;
|
||||||
|
*DirectoryMarkerAsNextOffset = DirectoryNextOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
except (EXCEPTION_EXECUTE_HANDLER)
|
except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
@ -323,9 +353,12 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache(
|
|||||||
FileDesc->DirInfo = FileNode->NonPaged->DirInfo;
|
FileDesc->DirInfo = FileNode->NonPaged->DirInfo;
|
||||||
|
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||||
|
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||||
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
|
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
|
||||||
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
|
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
|
||||||
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
|
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
|
||||||
|
UINT64 DirectoryMarkerAsNextOffset = 0;
|
||||||
PUINT8 DirInfoBgn = (PUINT8)DirInfo;
|
PUINT8 DirInfoBgn = (PUINT8)DirInfo;
|
||||||
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
|
PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize;
|
||||||
|
|
||||||
@ -334,8 +367,10 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache(
|
|||||||
|
|
||||||
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
|
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
|
||||||
0 != FileDesc->DirInfoCacheHint ? 0 : &FileDesc->DirectoryMarker, &DirectoryMarker,
|
0 != FileDesc->DirInfoCacheHint ? 0 : &FileDesc->DirectoryMarker, &DirectoryMarker,
|
||||||
|
FsvolDeviceExtension->VolumeParams.DirectoryMarkerAsNextOffset ?
|
||||||
|
&DirectoryMarkerAsNextOffset : 0,
|
||||||
FileInformationClass, ReturnSingleEntry,
|
FileInformationClass, ReturnSingleEntry,
|
||||||
!!FspFsvolDeviceExtension(FileNode->FsvolDeviceObject)->VolumeParams.ExtendedAttributes,
|
!!FsvolDeviceExtension->VolumeParams.ExtendedAttributes,
|
||||||
&DirInfo, DirInfoSize,
|
&DirInfo, DirInfoSize,
|
||||||
DestBuf, PDestLen);
|
DestBuf, PDestLen);
|
||||||
|
|
||||||
@ -366,10 +401,13 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
|
|||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
NTSTATUS Result;
|
NTSTATUS Result;
|
||||||
|
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension =
|
||||||
|
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject);
|
||||||
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
|
BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive;
|
||||||
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
|
PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern;
|
||||||
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
|
UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker;
|
||||||
FSP_FILE_NODE *FileNode = FileDesc->FileNode;
|
UINT64 DirectoryMarkerAsNextOffset = 0;
|
||||||
|
|
||||||
FSP_FSCTL_STATIC_ASSERT(
|
FSP_FSCTL_STATIC_ASSERT(
|
||||||
FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >=
|
FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >=
|
||||||
@ -378,8 +416,10 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace(
|
|||||||
|
|
||||||
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
|
Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive,
|
||||||
0, &DirectoryMarker,
|
0, &DirectoryMarker,
|
||||||
|
FsvolDeviceExtension->VolumeParams.DirectoryMarkerAsNextOffset ?
|
||||||
|
&DirectoryMarkerAsNextOffset : 0,
|
||||||
FileInformationClass, ReturnSingleEntry,
|
FileInformationClass, ReturnSingleEntry,
|
||||||
!!FspFsvolDeviceExtension(FileNode->FsvolDeviceObject)->VolumeParams.ExtendedAttributes,
|
!!FsvolDeviceExtension->VolumeParams.ExtendedAttributes,
|
||||||
&DirInfo, DirInfoSize,
|
&DirInfo, DirInfoSize,
|
||||||
DestBuf, PDestLen);
|
DestBuf, PDestLen);
|
||||||
|
|
||||||
|
@ -1079,6 +1079,7 @@ typedef struct
|
|||||||
PVPB SwapVpb;
|
PVPB SwapVpb;
|
||||||
FSP_DELAYED_WORK_ITEM DeleteVolumeDelayedWorkItem;
|
FSP_DELAYED_WORK_ITEM DeleteVolumeDelayedWorkItem;
|
||||||
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
FSP_FSCTL_VOLUME_PARAMS VolumeParams;
|
||||||
|
FSP_FSEXT_PROVIDER *Provider;
|
||||||
UNICODE_STRING VolumePrefix;
|
UNICODE_STRING VolumePrefix;
|
||||||
UNICODE_PREFIX_TABLE_ENTRY VolumePrefixEntry;
|
UNICODE_PREFIX_TABLE_ENTRY VolumePrefixEntry;
|
||||||
FSP_IOQ *Ioq;
|
FSP_IOQ *Ioq;
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
* the data structure used to store providers (currently 2 parallel
|
* the data structure used to store providers (currently 2 parallel
|
||||||
* arrays) must be revisited.
|
* arrays) must be revisited.
|
||||||
*/
|
*/
|
||||||
#define FSP_FSEXT_PROVIDER_COUNTMAX 4
|
#define FSP_FSEXT_PROVIDER_COUNTMAX 16
|
||||||
|
|
||||||
static KSPIN_LOCK FsextSpinLock = 0;
|
static KSPIN_LOCK FsextSpinLock = 0;
|
||||||
static UINT32 FsextControlCodes[FSP_FSEXT_PROVIDER_COUNTMAX];
|
static UINT32 FsextControlCodes[FSP_FSEXT_PROVIDER_COUNTMAX];
|
||||||
@ -37,23 +37,9 @@ static FSP_FSEXT_PROVIDER *FsextProviders[FSP_FSEXT_PROVIDER_COUNTMAX];
|
|||||||
static inline
|
static inline
|
||||||
FSP_FSEXT_PROVIDER *FspFsextProviderGet(UINT32 FsextControlCode)
|
FSP_FSEXT_PROVIDER *FspFsextProviderGet(UINT32 FsextControlCode)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
for (ULONG I = 0; FSP_FSEXT_PROVIDER_COUNTMAX > I; I++)
|
for (ULONG I = 0; FSP_FSEXT_PROVIDER_COUNTMAX > I; I++)
|
||||||
if (FsextControlCode == FsextControlCodes[I])
|
if (FsextControlCode == FsextControlCodes[I])
|
||||||
return FsextProviders[I];
|
return FsextProviders[I];
|
||||||
#else
|
|
||||||
/* unroll by hand */
|
|
||||||
FSP_FSCTL_STATIC_ASSERT(4 == FSP_FSEXT_PROVIDER_COUNTMAX,
|
|
||||||
"unrolled loop expects FsextProviders to have 4 elements");
|
|
||||||
if (FsextControlCode == FsextControlCodes[0])
|
|
||||||
return FsextProviders[0];
|
|
||||||
if (FsextControlCode == FsextControlCodes[1])
|
|
||||||
return FsextProviders[1];
|
|
||||||
if (FsextControlCode == FsextControlCodes[2])
|
|
||||||
return FsextProviders[2];
|
|
||||||
if (FsextControlCode == FsextControlCodes[3])
|
|
||||||
return FsextProviders[3];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -146,3 +132,56 @@ NTSTATUS FspFsextProviderRegister(FSP_FSEXT_PROVIDER *Provider)
|
|||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS FspFsextProviderTransact(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject,
|
||||||
|
FSP_FSCTL_TRANSACT_RSP *Response, FSP_FSCTL_TRANSACT_REQ **PRequest)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This function uses IoBuildDeviceIoControlRequest to build an IRP and then send it
|
||||||
|
* to the WinFsp driver. IoBuildDeviceIoControlRequest places the IRP in the IRP queue
|
||||||
|
* thus allowing it to be cancelled with CancelSynchronousIo.
|
||||||
|
*
|
||||||
|
* Special kernel APC's must be enabled:
|
||||||
|
* See https://www.osr.com/blog/2018/02/14/beware-iobuilddeviceiocontrolrequest/
|
||||||
|
*/
|
||||||
|
ASSERT(!KeAreAllApcsDisabled());
|
||||||
|
|
||||||
|
NTSTATUS Result;
|
||||||
|
IO_STATUS_BLOCK IoStatus;
|
||||||
|
PIRP Irp;
|
||||||
|
PIO_STACK_LOCATION IrpSp;
|
||||||
|
|
||||||
|
if (0 != PRequest)
|
||||||
|
*PRequest = 0;
|
||||||
|
|
||||||
|
if (0 == DeviceObject)
|
||||||
|
DeviceObject = IoGetRelatedDeviceObject(FileObject);
|
||||||
|
|
||||||
|
Irp = IoBuildDeviceIoControlRequest(FSP_FSCTL_TRANSACT_INTERNAL,
|
||||||
|
DeviceObject,
|
||||||
|
Response,
|
||||||
|
0 != Response ? Response->Size : 0,
|
||||||
|
PRequest,
|
||||||
|
0 != PRequest ? sizeof(PVOID) : 0,
|
||||||
|
FALSE,
|
||||||
|
0,
|
||||||
|
&IoStatus);
|
||||||
|
if (0 == Irp)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IoBuildDeviceIoControlRequest builds an IOCTL IRP without a FileObject.
|
||||||
|
* Patch it so that it is an FSCTL IRP with a FileObject. Mark it as
|
||||||
|
* IRP_SYNCHRONOUS_API so that CancelSynchronousIo can cancel it.
|
||||||
|
*/
|
||||||
|
Irp->Flags |= IRP_SYNCHRONOUS_API;
|
||||||
|
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||||||
|
IrpSp->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
|
||||||
|
IrpSp->MinorFunction = IRP_MN_USER_FS_REQUEST;
|
||||||
|
IrpSp->FileObject = FileObject;
|
||||||
|
|
||||||
|
Result = IoCallDriver(DeviceObject, Irp);
|
||||||
|
ASSERT(STATUS_PENDING != Result);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
@ -992,14 +992,13 @@ NTSTATUS FspVolumeTransactFsext(
|
|||||||
if (!FspDeviceReference(FsvolDeviceObject))
|
if (!FspDeviceReference(FsvolDeviceObject))
|
||||||
return STATUS_CANCELLED;
|
return STATUS_CANCELLED;
|
||||||
|
|
||||||
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
||||||
NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
|
NTSTATUS Result = STATUS_INVALID_DEVICE_REQUEST;
|
||||||
if (IrpSp->Parameters.FileSystemControl.FsControlCode ==
|
if (IrpSp->Parameters.FileSystemControl.FsControlCode ==
|
||||||
FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FsextControlCode)
|
FsvolDeviceExtension->VolumeParams.FsextControlCode)
|
||||||
{
|
{
|
||||||
FSP_FSEXT_PROVIDER *Provider = FspFsextProvider(
|
if (0 != FsvolDeviceExtension->Provider)
|
||||||
IrpSp->Parameters.FileSystemControl.FsControlCode, 0);
|
Result = FsvolDeviceExtension->Provider->DeviceTransact(FsvolDeviceObject, Irp);
|
||||||
if (0 != Provider)
|
|
||||||
Result = Provider->DeviceTransact(FsvolDeviceObject, Irp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FspDeviceDereference(FsvolDeviceObject);
|
FspDeviceDereference(FsvolDeviceObject);
|
||||||
|
0
tools/build-sample.bat
Normal file → Executable file
0
tools/build-sample.bat
Normal file → Executable file
@ -83,11 +83,11 @@ for %%f in (build\%Configuration%\winfsp-*.msi) do (
|
|||||||
|
|
||||||
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.
|
if not %signfail%==0 echo SIGNING FAILED! The product has been successfully built, but not signed.
|
||||||
|
|
||||||
|
for %%f in (build\%Configuration%\winfsp-*.msi) do set Version=%%~nf
|
||||||
|
set Version=!Version:winfsp-=!
|
||||||
|
|
||||||
where /q choco.exe
|
where /q choco.exe
|
||||||
if %ERRORLEVEL% equ 0 (
|
if %ERRORLEVEL% equ 0 (
|
||||||
for %%f in (build\%Configuration%\winfsp-*.msi) do set Version=%%~nf
|
|
||||||
set Version=!Version:winfsp-=!
|
|
||||||
|
|
||||||
copy ..\choco\* build\%Configuration%
|
copy ..\choco\* build\%Configuration%
|
||||||
copy ..\choco\LICENSE.TXT /B + ..\..\License.txt /B build\%Configuration%\LICENSE.txt /B
|
copy ..\choco\LICENSE.TXT /B + ..\..\License.txt /B build\%Configuration%\LICENSE.txt /B
|
||||||
certutil -hashfile build\%Configuration%\winfsp-!Version!.msi SHA256 >>build\%Configuration%\VERIFICATION.txt
|
certutil -hashfile build\%Configuration%\winfsp-!Version!.msi SHA256 >>build\%Configuration%\VERIFICATION.txt
|
||||||
@ -95,6 +95,11 @@ if %ERRORLEVEL% equ 0 (
|
|||||||
if errorlevel 1 goto fail
|
if errorlevel 1 goto fail
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pushd build\%Configuration%
|
||||||
|
powershell -command "Compress-Archive -Path winfsp-tests-*.exe,..\..\..\..\License.txt,..\..\..\..\tst\winfsp-tests\README.md -DestinationPath winfsp-tests-!Version!.zip"
|
||||||
|
if errorlevel 1 goto fail
|
||||||
|
popd
|
||||||
|
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
|
0
tools/fsreg.bat
Normal file → Executable file
0
tools/fsreg.bat
Normal file → Executable file
0
tools/impdef.bat
Normal file → Executable file
0
tools/impdef.bat
Normal file → Executable file
64
tst/winfsp-tests/README.md
Normal file
64
tst/winfsp-tests/README.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
## WINFSP-TESTS
|
||||||
|
|
||||||
|
Winfsp-tests is a file system test suite that is used to test WinFsp and the file systems that ship with it. It is not intended for use by end users. If you have downloaded winfsp-tests, you likely wanted to download the WinFsp installer instead (i.e. the file that is named `winfsp-VERSION.msi`).
|
||||||
|
|
||||||
|
**WINFSP-TESTS IS UNSUPPORTED SOFTWARE. IT MAY CRASH OR LOCK UP YOUR COMPUTER, CREATE ZOMBIE/UNKILLABLE PROCESSES OR CORRUPT YOUR DATA. DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING. DO NOT POST BUGS/ISSUES/QUESTIONS AGAINST WINFSP-TESTS UNLESS YOU ALSO POST THE FIX. YOU HAVE BEEN WARNED!**
|
||||||
|
|
||||||
|
## USAGE
|
||||||
|
|
||||||
|
Winfsp-tests has two different test modes: a default internal mode in which it runs its tests against an embedded copy of MEMFS and an external mode in which it runs its tests against the file system in the current directory.
|
||||||
|
|
||||||
|
Unless you are doing WinFsp development there should never be a need to run winfsp-tests in the default internal mode. However the external mode can be useful to test third party file systems that do not ship with WinFsp.
|
||||||
|
|
||||||
|
To run winfsp-tests in external mode, you must use the `--external` command line option. I also recommend using the `--resilient` command line option, to have winfsp-tests improve test flakiness by retrying failed operations.
|
||||||
|
|
||||||
|
```
|
||||||
|
> winfsp-tests-x64 --external --resilient
|
||||||
|
create_test............................ OK 0.00s
|
||||||
|
create_fileattr_test................... OK 0.00s
|
||||||
|
...
|
||||||
|
--- COMPLETE ---
|
||||||
|
```
|
||||||
|
|
||||||
|
Specific tests to be run may be specified. For example, to run all tests that start with `rename`:
|
||||||
|
|
||||||
|
```
|
||||||
|
> winfsp-tests-x64 --external --resilient rename*
|
||||||
|
rename_test............................ OK 0.01s
|
||||||
|
rename_open_test....................... OK 0.00s
|
||||||
|
...
|
||||||
|
--- COMPLETE ---
|
||||||
|
```
|
||||||
|
|
||||||
|
To exclude a test or tests use the `-` prefix. For example, to run all `create` tests, except the `create_fileattr_test`:
|
||||||
|
|
||||||
|
```
|
||||||
|
> winfsp-tests-x64 --external --resilient create* -create_fileattr_test
|
||||||
|
create_test............................ OK 0.05s
|
||||||
|
create_readonlydir_test................ OK 0.01s
|
||||||
|
...
|
||||||
|
--- COMPLETE ---
|
||||||
|
```
|
||||||
|
|
||||||
|
By default only regular tests are run. To include optional or long running tests use the `+` prefix. For example, to run all tests use `+*`; to run oplock tests use `+oplock*`:
|
||||||
|
|
||||||
|
```
|
||||||
|
> winfsp-tests-x64 --external --resilient +oplock*
|
||||||
|
oplock_level1_test..................... OK 1.26s
|
||||||
|
oplock_level2_test..................... OK 2.46s
|
||||||
|
...
|
||||||
|
--- COMPLETE ---
|
||||||
|
```
|
||||||
|
|
||||||
|
To list tests without running them use the `--list` option:
|
||||||
|
|
||||||
|
```
|
||||||
|
> winfsp-tests-x64 --external --resilient --list +oplock*
|
||||||
|
oplock_level1_test
|
||||||
|
oplock_level2_test
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
If a test fails the test suite stops immediately with an assertion failure. There is no additional explanation of the problem and you have to study the winfsp-tests source code to understand the failure and determine a fix for your file system. Additionally there may be garbage files remaining in the file system as winfsp-tests does not cleanup after itself.
|
||||||
|
|
||||||
|
**NOTE**: Some tests require Administrator privileges in order to run.
|
Reference in New Issue
Block a user