Compare commits

..

6 Commits

Author SHA1 Message Date
551ed341a7 build: version: 2022 Beta5 2021-12-20 14:57:13 +00:00
52ffb47fee build: fix broken version info 2021-12-08 10:37:33 +00:00
c208e0ecbd sys: cache FileDesc->DispositionStatus
DeleteFileW and RemoveDirectoryW in recent versions of Windows 10 have
been changed to perform a FileDispositionInformationEx with POSIX
semantics and if that fails to retry with FileDispositionInformation.
Unfortunately this is done even for legitimate error codes such as
STATUS_DIRECTORY_NOT_EMPTY.

This means that user mode file systems have to do unnecessary CanDelete
checks even when they support FileDispositionInformationEx. The extra
check incurs extra context switches, and in some cases it may also be
costly to compute (e.g. FUSE).

We optimize this away by storing the status of the last CanDelete check
in the FileDesc and then continue returning the same status code for
all checks for the same FileDesc.
2021-12-04 12:36:12 +00:00
87389f010b build: fix broken builds when FSD source changes
Turns out that the linker automatically creates .LIB and .EXP files
for all targets that export symbols (e.g. via __declspec(dllexport)).
The FSD now exports symbols for use by other kernel drivers; this
resulted in files like winfsp-x64.lib and winfsp-x64.exp to be
inadvertently created. Unfortunately this clashed with the files with
the same name created from building the DLL.

Since we only want the .LIB and .EXP files produced from the DLL, we
rename the .LIB and .EXP files produced from the FSD to a name that
does not clash. There does not seem to be any way to instruct the
linker to completely turn off .LIB and .EXP file generation for targets
that export symbols.
2021-12-04 08:36:54 +00:00
c32b1c19c2 sys: FspFsvolQueryDirectoryRetry: early exit when pattern not wild 2021-12-03 17:20:50 +00:00
8ce6836674 dll: FspFileSystemSearchDirectoryBuffer: fix #351 2021-12-03 14:47:19 +00:00
10 changed files with 275 additions and 19 deletions

View File

@ -19,7 +19,7 @@
<MyCanonicalVersion>1.10</MyCanonicalVersion> <MyCanonicalVersion>1.10</MyCanonicalVersion>
<MyProductVersion>2022 Beta4</MyProductVersion> <MyProductVersion>2022 Beta5</MyProductVersion>
<MyProductStage>Beta</MyProductStage> <MyProductStage>Beta</MyProductStage>
<MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion> <MyVersion>$(MyCanonicalVersion).$(MyBuildNumber)</MyVersion>
@ -39,7 +39,7 @@
<PreprocessorDefinitions>NTDDI_VERSION=0x06010000;_WIN32_WINNT=0x0601;MyProductName=$(MyProductName);MyProductFileName=$(MyProductFileName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas);MyFullVersion=$(MyFullVersion);MyFspFsctlDeviceClassGuid=$(MyFspFsctlDeviceClassGuid);MyFspFsvrtDeviceClassGuid=$(MyFspFsvrtDeviceClassGuid)</PreprocessorDefinitions> <PreprocessorDefinitions>NTDDI_VERSION=0x06010000;_WIN32_WINNT=0x0601;MyProductName=$(MyProductName);MyProductFileName=$(MyProductFileName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas);MyFullVersion=$(MyFullVersion);MyFspFsctlDeviceClassGuid=$(MyFspFsctlDeviceClassGuid);MyFspFsvrtDeviceClassGuid=$(MyFspFsvrtDeviceClassGuid)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>MyProductName=$(MyProductName);MyProductFileName=$(MyProductFileName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas);MyFullVersion=$(MyFullVersion)MyFspFsctlDeviceClassGuid=$(MyFspFsctlDeviceClassGuid);MyFspFsvrtDeviceClassGuid=$(MyFspFsvrtDeviceClassGuid)</PreprocessorDefinitions> <PreprocessorDefinitions>MyProductName=$(MyProductName);MyProductFileName=$(MyProductFileName);MyDescription=$(MyDescription);MyCompanyName=$(MyCompanyName);MyCopyright=$(MyCopyright);MyProductVersion=$(MyProductVersion);MyProductStage=$(MyProductStage);MyVersion=$(MyVersion);MyVersionWithCommas=$(MyVersionWithCommas);MyFullVersion=$(MyFullVersion);MyFspFsctlDeviceClassGuid=$(MyFspFsctlDeviceClassGuid);MyFspFsvrtDeviceClassGuid=$(MyFspFsvrtDeviceClassGuid)</PreprocessorDefinitions>
</ResourceCompile> </ResourceCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(IsKernelModeToolset)'=='true'"> <ItemDefinitionGroup Condition="'$(IsKernelModeToolset)'=='true'">

View File

@ -110,6 +110,7 @@
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
<ImportLibrary>$(OutDir)$(TargetName)$(TargetExt).lib</ImportLibrary>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -124,6 +125,7 @@
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
<AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions>
<ImportLibrary>$(OutDir)$(TargetName)$(TargetExt).lib</ImportLibrary>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -137,6 +139,7 @@
<ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile> <ProgramDatabaseFile>$(OutDir)$(TargetFileName).pdb</ProgramDatabaseFile>
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
<ImportLibrary>$(OutDir)$(TargetName)$(TargetExt).lib</ImportLibrary>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -151,6 +154,7 @@
<MapFileName>$(OutDir)$(TargetFileName).map</MapFileName> <MapFileName>$(OutDir)$(TargetFileName).map</MapFileName>
<StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols> <StripPrivateSymbols>$(OutDir)$(TargetFileName).public.pdb</StripPrivateSymbols>
<AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/PDBALTPATH:$(TargetFileName).pdb %(AdditionalOptions)</AdditionalOptions>
<ImportLibrary>$(OutDir)$(TargetName)$(TargetExt).lib</ImportLibrary>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>

View File

@ -114,7 +114,7 @@ static BOOLEAN FspFileSystemSearchDirectoryBuffer(FSP_FILE_SYSTEM_DIRECTORY_BUFF
} }
} }
*PIndexNum = Lo; *PIndexNum = Hi;
return FALSE; return FALSE;
} }

View File

@ -463,7 +463,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
PVOID DirInfoBuffer; PVOID DirInfoBuffer;
ULONG DirInfoSize; ULONG DirInfoSize;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
BOOLEAN PassQueryDirectoryPattern, PatternIsFileName; BOOLEAN PassQueryDirectoryPattern, PatternIsWild, PatternIsFileName;
BOOLEAN Success; BOOLEAN Success;
ASSERT(FileNode == FileDesc->FileNode); ASSERT(FileNode == FileDesc->FileNode);
@ -520,6 +520,14 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
return Result; return Result;
} }
/* if the pattern does not contain wildcards and we already returned a result, bail now! */
PatternIsWild = FsRtlDoesNameContainWildCards(&FileDesc->DirectoryPattern);
if (!PatternIsWild && FileDesc->DirectoryHasSuchFile)
{
FspFileNodeRelease(FileNode, Full);
return STATUS_NO_MORE_FILES;
}
/* see if the required information is still in the cache and valid! */ /* see if the required information is still in the cache and valid! */
if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize)) if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize))
{ {
@ -545,19 +553,10 @@ static NTSTATUS FspFsvolQueryDirectoryRetry(
/* special handling when pattern is filename */ /* special handling when pattern is filename */
PatternIsFileName = FsvolDeviceExtension->VolumeParams.PassQueryDirectoryFileName && PatternIsFileName = FsvolDeviceExtension->VolumeParams.PassQueryDirectoryFileName &&
!FsRtlDoesNameContainWildCards(&FileDesc->DirectoryPattern); !PatternIsWild;
PassQueryDirectoryPattern = PatternIsFileName || PassQueryDirectoryPattern = PatternIsFileName ||
(FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern && (FsvolDeviceExtension->VolumeParams.PassQueryDirectoryPattern &&
FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer); FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer);
if (PatternIsFileName &&
0 != FileDesc->DirectoryMarker.Buffer &&
0 == FspFileNameCompare(&FileDesc->DirectoryPattern, &FileDesc->DirectoryMarker,
!FileDesc->CaseSensitive, 0))
{
FspFileNodeRelease(FileNode, Full);
return !FileDesc->DirectoryHasSuchFile ?
STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
}
/* probe and lock the user buffer */ /* probe and lock the user buffer */
Result = FspLockUserBuffer(Irp, Length, IoWriteAccess); Result = FspLockUserBuffer(Irp, Length, IoWriteAccess);

View File

@ -1497,6 +1497,7 @@ typedef struct
DidSetFileAttributes:1, DidSetReparsePoint:1, DidSetSecurity:1, DidSetFileAttributes:1, DidSetReparsePoint:1, DidSetSecurity:1,
DidSetCreationTime:1, DidSetLastAccessTime:1, DidSetLastWriteTime:1, DidSetChangeTime:1, DidSetCreationTime:1, DidSetLastAccessTime:1, DidSetLastWriteTime:1, DidSetChangeTime:1,
DirectoryHasSuchFile:1; DirectoryHasSuchFile:1;
NTSTATUS DispositionStatus;
UNICODE_STRING DirectoryPattern; UNICODE_STRING DirectoryPattern;
UNICODE_STRING DirectoryMarker; UNICODE_STRING DirectoryMarker;
UINT64 DirInfo; UINT64 DirInfo;

View File

@ -83,6 +83,8 @@ static NTSTATUS FspFsvolSetDispositionInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolSetDispositionInformationSuccess( static NTSTATUS FspFsvolSetDispositionInformationSuccess(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response); PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
static NTSTATUS FspFsvolSetDispositionInformationFailure(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
static NTSTATUS FspFsvolSetRenameInformation( static NTSTATUS FspFsvolSetRenameInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolSetRenameInformationSuccess( static NTSTATUS FspFsvolSetRenameInformationSuccess(
@ -125,6 +127,7 @@ FAST_IO_QUERY_OPEN FspFastIoQueryOpen;
#pragma alloc_text(PAGE, FspFsvolSetPositionInformation) #pragma alloc_text(PAGE, FspFsvolSetPositionInformation)
#pragma alloc_text(PAGE, FspFsvolSetDispositionInformation) #pragma alloc_text(PAGE, FspFsvolSetDispositionInformation)
#pragma alloc_text(PAGE, FspFsvolSetDispositionInformationSuccess) #pragma alloc_text(PAGE, FspFsvolSetDispositionInformationSuccess)
#pragma alloc_text(PAGE, FspFsvolSetDispositionInformationFailure)
#pragma alloc_text(PAGE, FspFsvolSetRenameInformation) #pragma alloc_text(PAGE, FspFsvolSetRenameInformation)
#pragma alloc_text(PAGE, FspFsvolSetRenameInformationSuccess) #pragma alloc_text(PAGE, FspFsvolSetRenameInformationSuccess)
#pragma alloc_text(PAGE, FspFsvolSetInformation) #pragma alloc_text(PAGE, FspFsvolSetInformation)
@ -1567,6 +1570,27 @@ retry:
else else
DispositionFlags = FILE_DISPOSITION_DO_NOT_DELETE; DispositionFlags = FILE_DISPOSITION_DO_NOT_DELETE;
/*
* DeleteFileW and RemoveDirectoryW in recent versions of Windows 10 have been changed to
* perform a FileDispositionInformationEx with POSIX semantics and if that fails to retry
* with FileDispositionInformation. Unfortunately this is done even for legitimate error
* codes such as STATUS_DIRECTORY_NOT_EMPTY.
*
* This means that user mode file systems have to do unnecessary CanDelete checks even when
* they support FileDispositionInformationEx. The extra check incurs extra context switches,
* and in some cases it may also be costly to compute (e.g. FUSE).
*
* We optimize this away by storing the status of the last CanDelete check in the FileDesc
* and then continue returning the same status code for all checks for the same FileDesc.
*/
if (FILE_DISPOSITION_DELETE == (DispositionFlags & ~FILE_DISPOSITION_POSIX_SEMANTICS) &&
STATUS_SUCCESS != FileDesc->DispositionStatus)
{
Result = FileDesc->DispositionStatus;
goto unlock_exit;
}
FileDesc->DispositionStatus = STATUS_SUCCESS;
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, 0, Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, 0,
FspFsvolSetInformationRequestFini, &Request); FspFsvolSetInformationRequestFini, &Request);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
@ -1629,6 +1653,44 @@ static NTSTATUS FspFsvolSetDispositionInformationSuccess(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS FspFsvolSetDispositionInformationFailure(
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
{
PAGED_CODE();
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
UINT32 DispositionFlags = Request->Req.SetInformation.Info.DispositionEx.Flags;
/*
* DeleteFileW and RemoveDirectoryW in recent versions of Windows 10 have been changed to
* perform a FileDispositionInformationEx with POSIX semantics and if that fails to retry
* with FileDispositionInformation. Unfortunately this is done even for legitimate error
* codes such as STATUS_DIRECTORY_NOT_EMPTY.
*
* This means that user mode file systems have to do unnecessary CanDelete checks even when
* they support FileDispositionInformationEx. The extra check incurs extra context switches,
* and in some cases it may also be costly to compute (e.g. FUSE).
*
* We optimize this away by storing the status of the last CanDelete check in the FileDesc
* and then continue returning the same status code for all checks for the same FileDesc.
*/
switch (Response->IoStatus.Status)
{
case STATUS_ACCESS_DENIED:
case STATUS_DIRECTORY_NOT_EMPTY:
case STATUS_CANNOT_DELETE:
if (FILE_DISPOSITION_DELETE == (DispositionFlags & ~FILE_DISPOSITION_POSIX_SEMANTICS))
FileDesc->DispositionStatus = Response->IoStatus.Status;
break;
}
Irp->IoStatus.Information = 0;
return Response->IoStatus.Status;
}
static NTSTATUS FspFsvolSetRenameInformation( static NTSTATUS FspFsvolSetRenameInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{ {
@ -2095,15 +2157,23 @@ NTSTATUS FspFsvolSetInformationComplete(
{ {
FSP_ENTER_IOC(PAGED_CODE()); FSP_ENTER_IOC(PAGED_CODE());
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
if (!NT_SUCCESS(Response->IoStatus.Status)) if (!NT_SUCCESS(Response->IoStatus.Status))
{ {
/* special case FileDispositionInformation */
switch (FileInformationClass)
{
case FileDispositionInformation:
case FileDispositionInformationEx:
FSP_RETURN(Result = FspFsvolSetDispositionInformationFailure(Irp, Response));
}
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
Result = Response->IoStatus.Status; Result = Response->IoStatus.Status;
FSP_RETURN(); FSP_RETURN();
} }
FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.SetFile.FileInformationClass;
/* special case FileDispositionInformation/FileRenameInformation */ /* special case FileDispositionInformation/FileRenameInformation */
switch (FileInformationClass) switch (FileInformationClass)
{ {

View File

@ -889,6 +889,10 @@ if X%5==XNOEXCL (
-reparse* -stream* %~5 -reparse* -stream* %~5
) )
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
"%ProjRoot%\build\VStudio\build\%Configuration%\%4.exe" ^
--external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^
+querydir_single_test
if !ERRORLEVEL! neq 0 set RunSampleTestExit=1
popd popd
echo net use L: /delete echo net use L: /delete
net use L: /delete net use L: /delete

View File

@ -376,6 +376,94 @@ static void dirbuf_fill_test(void)
} }
} }
static void dirbuf_boundary_dotest(PWSTR Marker, ULONG ExpectI, ULONG ExpectN, ...)
{
PVOID DirBuffer = 0;
NTSTATUS Result;
BOOLEAN Success;
union
{
UINT8 B[sizeof(FSP_FSCTL_DIR_INFO) + MAX_PATH * sizeof(WCHAR)];
FSP_FSCTL_DIR_INFO D;
} DirInfoBuf;
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D, *DirInfoEnd;
UINT8 Buffer[1024];
ULONG Length, BytesTransferred;
WCHAR CurrFileName[MAX_PATH];
ULONG N;
PWSTR Name;
va_list Names0, Names1;
va_start(Names0, ExpectN);
va_copy(Names1, Names0);
Length = sizeof Buffer;
Result = STATUS_UNSUCCESSFUL;
Success = FspFileSystemAcquireDirectoryBuffer(&DirBuffer, FALSE, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
while (0 != (Name = va_arg(Names0, PWSTR)))
{
memset(&DirInfoBuf, 0, sizeof DirInfoBuf);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + wcslen(Name) * sizeof(WCHAR));
wcscpy_s(DirInfo->FileNameBuf, MAX_PATH, Name);
Success = FspFileSystemFillDirectoryBuffer(&DirBuffer, DirInfo, &Result);
ASSERT(Success);
ASSERT(STATUS_SUCCESS == Result);
}
FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
BytesTransferred = 0;
FspFileSystemReadDirectoryBuffer(&DirBuffer, Marker, Buffer, Length, &BytesTransferred);
for (N = 0; ExpectI > N; N++)
va_arg(Names1, PWSTR);
for (N = 0,
DirInfo = (PVOID)Buffer, DirInfoEnd = (PVOID)(Buffer + BytesTransferred);
DirInfoEnd > DirInfo && 0 != DirInfo->Size;
DirInfo = (PVOID)((PUINT8)DirInfo + FSP_FSCTL_DEFAULT_ALIGN_UP(DirInfo->Size)), N++)
{
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
Name = va_arg(Names1, PWSTR);
ASSERT(0 == wcscmp(CurrFileName, Name));
}
ASSERT(ExpectN == N);
FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
va_end(Names1);
va_end(Names0);
}
static void dirbuf_boundary_test(void)
{
dirbuf_boundary_dotest(L"A", 0, 0, 0);
dirbuf_boundary_dotest(L"A", 0, 1, L"B", 0);
dirbuf_boundary_dotest(L"B", 0, 0, L"B", 0);
dirbuf_boundary_dotest(L"C", 0, 0, L"B", 0);
dirbuf_boundary_dotest(L"A", 0, 2, L"B", L"D", 0);
dirbuf_boundary_dotest(L"B", 1, 1, L"B", L"D", 0);
dirbuf_boundary_dotest(L"C", 1, 1, L"B", L"D", 0);
dirbuf_boundary_dotest(L"D", 0, 0, L"B", L"D", 0);
dirbuf_boundary_dotest(L"E", 0, 0, L"B", L"D", 0);
dirbuf_boundary_dotest(L"A", 0, 3, L"B", L"D", L"F", 0);
dirbuf_boundary_dotest(L"B", 1, 2, L"B", L"D", L"F", 0);
dirbuf_boundary_dotest(L"C", 1, 2, L"B", L"D", L"F", 0);
dirbuf_boundary_dotest(L"D", 2, 1, L"B", L"D", L"F", 0);
dirbuf_boundary_dotest(L"E", 2, 1, L"B", L"D", L"F", 0);
dirbuf_boundary_dotest(L"F", 0, 0, L"B", L"D", L"F", 0);
dirbuf_boundary_dotest(L"G", 0, 0, L"B", L"D", L"F", 0);
}
void dirbuf_tests(void) void dirbuf_tests(void)
{ {
if (OptExternal) if (OptExternal)
@ -384,4 +472,5 @@ void dirbuf_tests(void)
TEST(dirbuf_empty_test); TEST(dirbuf_empty_test);
TEST(dirbuf_dots_test); TEST(dirbuf_dots_test);
TEST(dirbuf_fill_test); TEST(dirbuf_fill_test);
TEST(dirbuf_boundary_test);
} }

View File

@ -269,6 +269,93 @@ void querydir_test(void)
} }
} }
static void querydir_single_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout, ULONG SleepTimeout)
{
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
HANDLE Handle;
BOOL Success;
WCHAR CurrentDirectory[MAX_PATH], FileName[MAX_PATH];
WIN32_FIND_DATAW FindData;
StringCbPrintfW(FileName, sizeof FileName, L"%s%s\\",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = GetCurrentDirectoryW(MAX_PATH, CurrentDirectory);
ASSERT(Success);
Success = SetCurrentDirectoryW(FileName);
ASSERT(Success);
for (ULONG Index = 0; 1000 > Index; Index++)
{
StringCbPrintfW(FileName, sizeof FileName, L"xxxxxxx-file%lu", Index);
Handle = CreateFileW(FileName,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL,
0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Success = CloseHandle(Handle);
ASSERT(Success);
}
Handle = FindFirstFileW(L"*", &FindData);
ASSERT(INVALID_HANDLE_VALUE != Handle);
do
{
} while (FindNextFileW(Handle, &FindData));
Success = FindClose(Handle);
ASSERT(Success);
for (ULONG Index = 0; 1000 > Index; Index++)
{
StringCbPrintfW(FileName, sizeof FileName, L"xxxxxxx-file%lu", Index);
Handle = FindFirstFileW(FileName, &FindData);
ASSERT(INVALID_HANDLE_VALUE != Handle);
do
{
} while (FindNextFileW(Handle, &FindData));
Success = FindClose(Handle);
ASSERT(Success);
}
for (ULONG Index = 0; 1000 > Index; Index++)
{
StringCbPrintfW(FileName, sizeof FileName, L"xxxxxxx-file%lu", Index);
Success = DeleteFileW(FileName);
ASSERT(Success);
}
Success = RealSetCurrentDirectoryW(CurrentDirectory);
ASSERT(Success);
memfs_stop(memfs);
}
void querydir_single_test(void)
{
if (OptShareName)
return;
if (NtfsTests)
{
WCHAR DirBuf[MAX_PATH];
GetTestDirectory(DirBuf);
querydir_single_dotest(-1, DirBuf, 0, 0);
}
if (WinFspDiskTests)
{
querydir_single_dotest(MemfsDisk, 0, 0, 0);
querydir_single_dotest(MemfsDisk, 0, 1000, 0);
}
if (WinFspNetTests)
{
querydir_single_dotest(MemfsNet, L"\\\\memfs\\share", 0, 0);
querydir_single_dotest(MemfsNet, L"\\\\memfs\\share", 1000, 0);
}
}
void querydir_expire_cache_test(void) void querydir_expire_cache_test(void)
{ {
if (WinFspDiskTests) if (WinFspDiskTests)
@ -645,6 +732,8 @@ void dirnotify_test(void)
void dirctl_tests(void) void dirctl_tests(void)
{ {
TEST(querydir_test); TEST(querydir_test);
if (!OptShareName)
TEST_OPT(querydir_single_test);
TEST(querydir_expire_cache_test); TEST(querydir_expire_cache_test);
if (!OptShareName) if (!OptShareName)
TEST(querydir_buffer_overflow_test); TEST(querydir_buffer_overflow_test);

View File

@ -50,7 +50,7 @@ static VOID PrepareFileName(PCWSTR FileName, PWSTR FileNameBuf)
else if (testalpha(FileNameBuf[0]) && L':' == FileNameBuf[1] && L'\\' == FileNameBuf[2]) else if (testalpha(FileNameBuf[0]) && L':' == FileNameBuf[1] && L'\\' == FileNameBuf[2])
P = FileNameBuf + 2; P = FileNameBuf + 2;
else else
ABORT("unknown filename format"); P = FileNameBuf;
for (EndP = P + wcslen(P); EndP > P; P++) for (EndP = P + wcslen(P); EndP > P; P++)
if (testalpha(*P) && myrand() <= (TogglePercent) * 0x7fff / 100) if (testalpha(*P) && myrand() <= (TogglePercent) * 0x7fff / 100)
@ -71,7 +71,7 @@ static VOID PrepareFileName(PCWSTR FileName, PWSTR FileNameBuf)
else if (testalpha(FileNameBuf[0]) && L':' == FileNameBuf[1] && L'\\' == FileNameBuf[2]) else if (testalpha(FileNameBuf[0]) && L':' == FileNameBuf[1] && L'\\' == FileNameBuf[2])
ABORT("--mountpoint not supported with NTFS"); ABORT("--mountpoint not supported with NTFS");
else else
ABORT("unknown filename format"); P = FileNameBuf;
L1 = wcslen(P) + 1; L1 = wcslen(P) + 1;
L2 = wcslen(OptMountPoint); L2 = wcslen(OptMountPoint);
@ -96,7 +96,7 @@ static VOID PrepareFileName(PCWSTR FileName, PWSTR FileNameBuf)
/* NTFS testing can only been done when the whole drive is being shared */ /* NTFS testing can only been done when the whole drive is being shared */
P = FileNameBuf + 2; P = FileNameBuf + 2;
else else
ABORT("unknown filename format"); P = FileNameBuf;
L1 = wcslen(P) + 1; L1 = wcslen(P) + 1;
L2 = wcslen(OptShareComputer); L2 = wcslen(OptShareComputer);