From 7843c73d34fa84604d46f41129565bab8be9a21a Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Tue, 24 Jan 2017 18:10:13 -0800 Subject: [PATCH] sys,dll: ReadDirectory: add Marker, remove Offset --- inc/winfsp/fsctl.h | 5 +- inc/winfsp/winfsp.h | 24 ++----- src/dll/debug.c | 9 ++- src/dll/fsop.c | 3 +- src/dll/fuse/fuse_intf.c | 7 +- src/sys/dirctl.c | 135 ++++++++++++++++++++++--------------- src/sys/driver.h | 8 ++- src/sys/file.c | 63 +++++++++++++++-- tst/memfs/memfs.cpp | 141 ++++----------------------------------- 9 files changed, 178 insertions(+), 217 deletions(-) diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index f50b48b8..2977f300 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -185,8 +185,7 @@ typedef struct { UINT16 Size; FSP_FSCTL_FILE_INFO FileInfo; - UINT64 NextOffset; - UINT8 Padding[16]; + UINT8 Padding[24]; /* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */ WCHAR FileNameBuf[]; } FSP_FSCTL_DIR_INFO; @@ -339,9 +338,9 @@ typedef struct UINT64 UserContext; UINT64 UserContext2; UINT64 Address; - UINT64 Offset; UINT32 Length; FSP_FSCTL_TRANSACT_BUF Pattern; + FSP_FSCTL_TRANSACT_BUF Marker; UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */ } QueryDirectory; struct diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h index b3c11ba2..c5b5b664 100644 --- a/inc/winfsp/winfsp.h +++ b/inc/winfsp/winfsp.h @@ -649,28 +649,16 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE * The file context of the directory to be read. * @param Buffer * Pointer to a buffer that will receive the results of the read operation. - * @param Offset - * Offset within the directory to read from. The kernel does not interpret this value - * which is used solely by the file system to locate directory entries. However the - * special value 0 indicates that the read should start from the first entries. The first - * two entries returned by ReadDirectory should always be the "." and ".." entries, - * except for the root directory which does not have these entries. - * - * This parameter is used by the WinFsp FSD to break directory listings into chunks. - * In this case all 64-bits of the Offset are valid. In some cases the Windows kernel - * (NTOS) may also use this parameter. In this case only the lower 32-bits of this - * parameter will be valid. This is an unfortunate limitation of Windows (for more - * information see the documentation for IRP_MJ_DIRECTORY_CONTROL and the flag - * SL_INDEX_SPECIFIED). - * - * In practice this means that you should only rely on the lower 32-bits of this value - * to be valid. * @param Length * Length of data to read. * @param Pattern * The pattern to match against files in this directory. Can be NULL. The file system * can choose to ignore this parameter as the FSD will always perform its own pattern * matching on the returned results. + * @param Marker + * A file name that marks where in the directory to start reading. Files with names + * that are greater than (not equal to) this marker (in the directory order determined + * by the file system) should be returned. Can be NULL. * @param PBytesTransferred [out] * Pointer to a memory location that will receive the actual number of bytes read. * @return @@ -680,8 +668,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE * FspFileSystemAddDirInfo */ NTSTATUS (*ReadDirectory)(FSP_FILE_SYSTEM *FileSystem, - PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length, - PWSTR Pattern, + PVOID FileContext, PVOID Buffer, ULONG Length, + PWSTR Pattern, PWSTR Marker, PULONG PBytesTransferred); /** * Resolve reparse points. diff --git a/src/dll/debug.c b/src/dll/debug.c index 2f764bf0..adf42ebf 100644 --- a/src/dll/debug.c +++ b/src/dll/debug.c @@ -518,7 +518,7 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request) break; case FspFsctlTransactQueryDirectoryKind: FspDebugLog("%S[TID=%04lx]: %p: >>QueryDirectory %s%S%s%s, " - "Address=%p, Offset=%lx:%lx, Length=%ld, Pattern=%s%S%s\n", + "Address=%p, Length=%ld, Pattern=%s%S%s, Marker=%s%S%s\n", FspDiagIdent(), GetCurrentThreadId(), Request->Hint, Request->FileName.Size ? "\"" : "", Request->FileName.Size ? (PWSTR)Request->Buffer : L"", @@ -527,12 +527,15 @@ FSP_API VOID FspDebugLogRequest(FSP_FSCTL_TRANSACT_REQ *Request) Request->Req.QueryDirectory.UserContext, Request->Req.QueryDirectory.UserContext2, UserContextBuf), Request->Req.QueryDirectory.Address, - MAKE_UINT32_PAIR(Request->Req.QueryDirectory.Offset), Request->Req.QueryDirectory.Length, Request->Req.QueryDirectory.Pattern.Size ? "\"" : "", Request->Req.QueryDirectory.Pattern.Size ? (PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : L"NULL", - Request->Req.QueryDirectory.Pattern.Size ? "\"" : ""); + Request->Req.QueryDirectory.Pattern.Size ? "\"" : "", + Request->Req.QueryDirectory.Marker.Size ? "\"" : "", + Request->Req.QueryDirectory.Marker.Size ? + (PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : L"NULL", + Request->Req.QueryDirectory.Marker.Size ? "\"" : ""); break; case FspFsctlTransactFileSystemControlKind: switch (Request->Req.FileSystemControl.FsControlCode) diff --git a/src/dll/fsop.c b/src/dll/fsop.c index 768bc05e..a5a2ed8c 100644 --- a/src/dll/fsop.c +++ b/src/dll/fsop.c @@ -1134,10 +1134,11 @@ FSP_API NTSTATUS FspFileSystemOpQueryDirectory(FSP_FILE_SYSTEM *FileSystem, Result = FileSystem->Interface->ReadDirectory(FileSystem, (PVOID)ValOfFileContext(Request->Req.QueryDirectory), (PVOID)Request->Req.QueryDirectory.Address, - Request->Req.QueryDirectory.Offset, Request->Req.QueryDirectory.Length, 0 != Request->Req.QueryDirectory.Pattern.Size ? (PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset) : 0, + 0 != Request->Req.QueryDirectory.Marker.Size ? + (PWSTR)(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset) : 0, &BytesTransferred); if (!NT_SUCCESS(Result)) return Result; diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index 3efbc0bb..a4b12f7f 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -1661,10 +1661,12 @@ int fsp_fuse_intf_AddDirInfoOld(fuse_dirh_t dh, const char *name, } static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem, - PVOID FileNode, PVOID Buffer, UINT64 Offset, ULONG Length, - PWSTR Pattern, + PVOID FileContext, PVOID Buffer, ULONG Length, + PWSTR Pattern, PWSTR Marker, PULONG PBytesTransferred) { + return STATUS_INVALID_DEVICE_REQUEST; +#if 0 struct fuse *f = FileSystem->UserContext; struct fsp_fuse_file_desc *filedesc = FileNode; struct fuse_file_info fi; @@ -1844,6 +1846,7 @@ exit: MemFree(dh.Buffer); return Result; +#endif } static NTSTATUS fsp_fuse_intf_ResolveReparsePoints(FSP_FILE_SYSTEM *FileSystem, diff --git a/src/sys/dirctl.c b/src/sys/dirctl.c index be52b85d..bb6d95c3 100644 --- a/src/sys/dirctl.c +++ b/src/sys/dirctl.c @@ -28,7 +28,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive, - UINT64 DirectoryOffset, PUINT64 PDirectoryOffset, + PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize, PVOID DestBuf, PULONG PDestLen); @@ -74,9 +74,6 @@ FSP_DRIVER_DISPATCH FspDirectoryControl; #pragma alloc_text(PAGE, FspDirectoryControl) #endif -#define FILE_INDEX_FROM_OFFSET(v) ((ULONG)(v)) -#define OFFSET_FROM_FILE_INDEX(v) ((UINT64)(v)) - enum { /* QueryDirectory */ @@ -94,7 +91,7 @@ enum static NTSTATUS FspFsvolQueryDirectoryCopy( PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive, - UINT64 DirectoryOffset, PUINT64 PDirectoryOffset, + PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize, PVOID DestBuf, PULONG PDestLen) @@ -104,7 +101,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( {\ TYPE InfoStruct = { 0 }, *Info = &InfoStruct;\ Info->NextEntryOffset = 0;\ - Info->FileIndex = FILE_INDEX_FROM_OFFSET(DirInfo->NextOffset);\ + Info->FileIndex = 0;\ Info->FileNameLength = FileName.Length;\ __VA_ARGS__\ Info = DestBuf;\ @@ -128,7 +125,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( NTSTATUS Result = STATUS_SUCCESS; BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer, Match; - BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE; + BOOLEAN Loop = TRUE, DirectoryMarkerFound = FALSE; FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo; PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize; PUINT8 DestBufBgn = (PUINT8)DestBuf; @@ -178,16 +175,18 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( break; } - if (0 != DirectoryOffset && !DirectoryOffsetFound) - { - DirectoryOffsetFound = DirInfo->NextOffset == DirectoryOffset; - continue; - } - FileName.Length = FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO)); FileName.Buffer = DirInfo->FileNameBuf; + if (0 != DirectoryMarker && 0 != DirectoryMarker->Buffer && + !DirectoryMarkerFound) + { + DirectoryMarkerFound = 0 == FspFileNameCompare( + &FileName, DirectoryMarker, CaseInsensitive, 0); + continue; + } + /* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */ CopyLength = FileName.Length; @@ -223,7 +222,6 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( *(PULONG)PrevDestBuf = (ULONG)((PUINT8)DestBuf - (PUINT8)PrevDestBuf); PrevDestBuf = DestBuf; - *PDirectoryOffset = DirInfo->NextOffset; *PDestLen = (ULONG)((PUINT8)DestBuf + BaseInfoLen + CopyLength - DestBufBgn); switch (FileInformationClass) @@ -265,6 +263,9 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( break; } + DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = FileName.Length; + DirectoryMarkerOut->Buffer = (PVOID)((PUINT8)DestBuf + BaseInfoLen); + DestBuf = (PVOID)((PUINT8)DestBuf + FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG))); @@ -273,7 +274,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( Loop = FALSE; } else - *PDirectoryOffset = DirInfo->NextOffset; + *DirectoryMarkerOut = FileName; } } except (EXCEPTION_EXECUTE_HANDLER) @@ -315,7 +316,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache( NTSTATUS Result; BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive; PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern; - UINT64 DirectoryOffset = FileDesc->DirectoryOffset; + UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker; PUINT8 DirInfoBgn = (PUINT8)DirInfo; PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize; @@ -323,17 +324,20 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache( DirInfoSize = (ULONG)(DirInfoEnd - (PUINT8)DirInfo); Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive, - 0 != FileDesc->DirInfoCacheHint ? 0 : DirectoryOffset, &DirectoryOffset, + 0 != FileDesc->DirInfoCacheHint ? 0 : &FileDesc->DirectoryMarker, &DirectoryMarker, FileInformationClass, ReturnSingleEntry, &DirInfo, DirInfoSize, DestBuf, PDestLen); if (NT_SUCCESS(Result)) { - if (0 != *PDestLen) - FileDesc->DirectoryHasSuchFile = TRUE; - FileDesc->DirectoryOffset = DirectoryOffset; - FileDesc->DirInfoCacheHint = (ULONG)((PUINT8)DirInfo - DirInfoBgn); + Result = FspFileDescSetDirectoryMarker(FileDesc, &DirectoryMarker); + if (NT_SUCCESS(Result)) + { + if (0 != *PDestLen) + FileDesc->DirectoryHasSuchFile = TRUE; + FileDesc->DirInfoCacheHint = (ULONG)((PUINT8)DirInfo - DirInfoBgn); + } } else if (STATUS_NO_MORE_FILES == Result && !FileDesc->DirectoryHasSuchFile) Result = STATUS_NO_SUCH_FILE; @@ -354,7 +358,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace( NTSTATUS Result; BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive; PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern; - UINT64 DirectoryOffset = FileDesc->DirectoryOffset; + UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker; ASSERT(DirInfo == DestBuf); FSP_FSCTL_STATIC_ASSERT( @@ -363,16 +367,19 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace( "FSP_FSCTL_DIR_INFO must be bigger than FILE_ID_BOTH_DIR_INFORMATION"); Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive, - 0, &DirectoryOffset, + 0, &DirectoryMarker, FileInformationClass, ReturnSingleEntry, &DirInfo, DirInfoSize, DestBuf, PDestLen); if (NT_SUCCESS(Result)) { - if (0 != *PDestLen) - FileDesc->DirectoryHasSuchFile = TRUE; - FileDesc->DirectoryOffset = DirectoryOffset; + Result = FspFileDescSetDirectoryMarker(FileDesc, &DirectoryMarker); + if (NT_SUCCESS(Result)) + { + if (0 != *PDestLen) + FileDesc->DirectoryHasSuchFile = TRUE; + } } else if (STATUS_NO_MORE_FILES == Result && !FileDesc->DirectoryHasSuchFile) Result = STATUS_NO_SUCH_FILE; @@ -442,7 +449,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry( * counter-productive to try to read more than we need. */ #define GetSystemBufferLengthMaybeCached()\ - (0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && 0 == FileDesc->DirectoryOffset) ||\ + (0 != FsvolDeviceExtension->VolumeParams.FileInfoTimeout && 0 == FileDesc->DirectoryMarker.Buffer) ||\ FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ?\ FspFsvolDeviceDirInfoCacheItemSizeMax : Length #define GetSystemBufferLengthNonCached()\ @@ -463,7 +470,7 @@ static NTSTATUS FspFsvolQueryDirectoryRetry( BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY); FILE_INFORMATION_CLASS FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass; PUNICODE_STRING FileName = IrpSp->Parameters.QueryDirectory.FileName; - ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex; + //ULONG FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex; PVOID Buffer = 0 != Irp->AssociatedIrp.SystemBuffer ? Irp->AssociatedIrp.SystemBuffer : Irp->UserBuffer; ULONG Length = IrpSp->Parameters.QueryDirectory.Length; @@ -511,27 +518,14 @@ static NTSTATUS FspFsvolQueryDirectoryRetry( Request = 0; } - /* set the DirectoryPattern in the FileDesc */ - Result = FspFileDescResetDirectoryPattern(FileDesc, FileName, - RestartScan && 0 != FileName && 0 != FileName->Length); + /* reset the FileDesc */ + Result = FspFileDescResetDirectory(FileDesc, FileName, RestartScan, IndexSpecified); if (!NT_SUCCESS(Result)) { FspFileNodeRelease(FileNode, Full); return Result; } - /* determine where to (re)start */ - if (IndexSpecified) - { - FileDesc->DirectoryHasSuchFile = FALSE; - FileDesc->DirectoryOffset = OFFSET_FROM_FILE_INDEX(FileIndex); - } - else if (RestartScan) - { - FileDesc->DirectoryHasSuchFile = FALSE; - FileDesc->DirectoryOffset = 0; - } - /* see if the required information is still in the cache and valid! */ if (FspFileNodeReferenceDirInfo(FileNode, &DirInfoBuffer, &DirInfoSize)) { @@ -571,8 +565,9 @@ static NTSTATUS FspFsvolQueryDirectoryRetry( /* create request */ Result = FspIopCreateRequestEx(Irp, 0, - FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ? - FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0, + (FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer ? + FileDesc->DirectoryPattern.Length + sizeof(WCHAR) : 0) + + (FsvolDeviceExtension->VolumeParams.MaxComponentLength + 1) * sizeof(WCHAR), FspFsvolQueryDirectoryRequestFini, &Request); if (!NT_SUCCESS(Result)) { @@ -583,19 +578,37 @@ static NTSTATUS FspFsvolQueryDirectoryRetry( Request->Kind = FspFsctlTransactQueryDirectoryKind; Request->Req.QueryDirectory.UserContext = FileNode->UserContext; Request->Req.QueryDirectory.UserContext2 = FileDesc->UserContext2; - Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset; Request->Req.QueryDirectory.Length = SystemBufferLength; Request->Req.QueryDirectory.CaseSensitive = FileDesc->CaseSensitive; if (FspFileDescDirectoryPatternMatchAll != FileDesc->DirectoryPattern.Buffer) { - Request->Req.QueryDirectory.Pattern.Offset = Request->FileName.Size; + Request->Req.QueryDirectory.Pattern.Offset = + Request->FileName.Size; Request->Req.QueryDirectory.Pattern.Size = FileDesc->DirectoryPattern.Length + sizeof(WCHAR); - RtlCopyMemory(Request->Buffer + Request->FileName.Size, + RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Pattern.Offset, FileDesc->DirectoryPattern.Buffer, FileDesc->DirectoryPattern.Length); - *(PWSTR)(Request->Buffer + Request->FileName.Size + FileDesc->DirectoryPattern.Length) = - L'\0'; + *(PWSTR)(Request->Buffer + + Request->Req.QueryDirectory.Pattern.Offset + + FileDesc->DirectoryPattern.Length) = L'\0'; + } + + if (0 != FileDesc->DirectoryMarker.Buffer) + { + ASSERT( + FsvolDeviceExtension->VolumeParams.MaxComponentLength >= + FileDesc->DirectoryMarker.Length); + + Request->Req.QueryDirectory.Marker.Offset = + Request->FileName.Size + Request->Req.QueryDirectory.Pattern.Size; + Request->Req.QueryDirectory.Marker.Size = + FileDesc->DirectoryMarker.Length + sizeof(WCHAR); + RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset, + FileDesc->DirectoryMarker.Buffer, FileDesc->DirectoryMarker.Length); + *(PWSTR)(Request->Buffer + + Request->Req.QueryDirectory.Marker.Offset + + FileDesc->DirectoryMarker.Length) = L'\0'; } FspFileNodeSetOwner(FileNode, Full, Request); @@ -885,7 +898,6 @@ NTSTATUS FspFsvolDirectoryControlComplete( BOOLEAN Success; ASSERT(FileNode == FileDesc->FileNode); - ASSERT(Request->Req.QueryDirectory.Offset == FileDesc->DirectoryOffset); if (0 == Response->IoStatus.Information) { @@ -913,7 +925,7 @@ NTSTATUS FspFsvolDirectoryControlComplete( FSP_RETURN(); } - if (0 == FileDesc->DirectoryOffset && + if (0 == Request->Req.QueryDirectory.Marker.Size && FspFileNodeTrySetDirInfo(FileNode, Irp->AssociatedIrp.SystemBuffer, (ULONG)Response->IoStatus.Information, @@ -952,7 +964,24 @@ NTSTATUS FspFsvolDirectoryControlComplete( FspIopResetRequest(Request, FspFsvolQueryDirectoryRequestFini); Request->Req.QueryDirectory.Address = 0; - Request->Req.QueryDirectory.Offset = FileDesc->DirectoryOffset; + Request->Req.QueryDirectory.Marker.Offset = 0; + Request->Req.QueryDirectory.Marker.Size = 0; + if (0 != FileDesc->DirectoryMarker.Buffer) + { + ASSERT( + FsvolDeviceExtension->VolumeParams.MaxComponentLength >= + FileDesc->DirectoryMarker.Length); + + Request->Req.QueryDirectory.Marker.Offset = + Request->FileName.Size + Request->Req.QueryDirectory.Pattern.Size; + Request->Req.QueryDirectory.Marker.Size = + FileDesc->DirectoryMarker.Length + sizeof(WCHAR); + RtlCopyMemory(Request->Buffer + Request->Req.QueryDirectory.Marker.Offset, + FileDesc->DirectoryMarker.Buffer, FileDesc->DirectoryMarker.Length); + *(PWSTR)(Request->Buffer + + Request->Req.QueryDirectory.Marker.Offset + + FileDesc->DirectoryMarker.Length) = L'\0'; + } FspFileNodeSetOwner(FileNode, Full, Request); FspIopRequestContext(Request, RequestIrp) = Irp; diff --git a/src/sys/driver.h b/src/sys/driver.h index 5babd58c..15b1c756 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -1231,7 +1231,7 @@ typedef struct DidSetCreationTime:1, DidSetLastAccessTime:1, DidSetLastWriteTime:1, DidSetChangeTime:1, DirectoryHasSuchFile:1; UNICODE_STRING DirectoryPattern; - UINT64 DirectoryOffset; + UNICODE_STRING DirectoryMarker; UINT64 DirInfo; ULONG DirInfoCacheHint; /* stream support */ @@ -1362,8 +1362,10 @@ VOID FspFileNodeNotifyChange(FSP_FILE_NODE *FileNode, ULONG Filter, ULONG Action NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp); NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc); VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); -NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, - PUNICODE_STRING FileName, BOOLEAN Reset); +NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc, + PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified); +NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc, + PUNICODE_STRING FileName); NTSTATUS FspMainFileOpen( PDEVICE_OBJECT FsvolDeviceObject, PDEVICE_OBJECT DeviceObjectHint, diff --git a/src/sys/file.c b/src/sys/file.c index eea11356..ad130caf 100644 --- a/src/sys/file.c +++ b/src/sys/file.c @@ -84,8 +84,10 @@ NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp); static NTSTATUS FspFileNodeCompleteLockIrp(PVOID Context, PIRP Irp); NTSTATUS FspFileDescCreate(FSP_FILE_DESC **PFileDesc); VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc); -NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, - PUNICODE_STRING FileName, BOOLEAN Reset); +NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc, + PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified); +NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc, + PUNICODE_STRING FileName); NTSTATUS FspMainFileOpen( PDEVICE_OBJECT FsvolDeviceObject, PDEVICE_OBJECT DeviceObjectHint, @@ -147,7 +149,8 @@ VOID FspFileNodeOplockComplete(PVOID Context, PIRP Irp); #pragma alloc_text(PAGE, FspFileNodeCompleteLockIrp) #pragma alloc_text(PAGE, FspFileDescCreate) #pragma alloc_text(PAGE, FspFileDescDelete) -#pragma alloc_text(PAGE, FspFileDescResetDirectoryPattern) +#pragma alloc_text(PAGE, FspFileDescResetDirectory) +#pragma alloc_text(PAGE, FspFileDescSetDirectoryMarker) #pragma alloc_text(PAGE, FspMainFileOpen) #pragma alloc_text(PAGE, FspMainFileClose) #pragma alloc_text(PAGE, FspFileNodeOplockPrepare) @@ -1984,15 +1987,19 @@ VOID FspFileDescDelete(FSP_FILE_DESC *FileDesc) RtlFreeUnicodeString(&FileDesc->DirectoryPattern); } + if (0 != FileDesc->DirectoryMarker.Buffer) + FspFree(FileDesc->DirectoryMarker.Buffer); + FspFree(FileDesc); } -NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, - PUNICODE_STRING FileName, BOOLEAN Reset) +NTSTATUS FspFileDescResetDirectory(FSP_FILE_DESC *FileDesc, + PUNICODE_STRING FileName, BOOLEAN RestartScan, BOOLEAN IndexSpecified) { PAGED_CODE(); - if (Reset || 0 == FileDesc->DirectoryPattern.Buffer) + if (0 == FileDesc->DirectoryPattern.Buffer || + (RestartScan && 0 != FileName && 0 != FileName->Length)) { UNICODE_STRING DirectoryPattern; @@ -2029,7 +2036,51 @@ NTSTATUS FspFileDescResetDirectoryPattern(FSP_FILE_DESC *FileDesc, } FileDesc->DirectoryPattern = DirectoryPattern; + FileDesc->DirectoryHasSuchFile = FALSE; + + if (0 != FileDesc->DirectoryMarker.Buffer) + { + FspFree(FileDesc->DirectoryMarker.Buffer); + FileDesc->DirectoryMarker.Buffer = 0; + } } + else if (IndexSpecified && 0 != FileName && 0 != FileName->Length) + { + NTSTATUS Result; + + Result = FspFileDescSetDirectoryMarker(FileDesc, FileName); + if (!NT_SUCCESS(Result)) + return Result; + + FileDesc->DirectoryHasSuchFile = FALSE; + } + + return STATUS_SUCCESS; +} + +NTSTATUS FspFileDescSetDirectoryMarker(FSP_FILE_DESC *FileDesc, + PUNICODE_STRING FileName) +{ + if (&FileDesc->DirectoryMarker == FileName) + return STATUS_SUCCESS; + + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = + FspFsvolDeviceExtension(FileDesc->FileNode->FsvolDeviceObject); + UNICODE_STRING DirectoryMarker; + + if (FsvolDeviceExtension->VolumeParams.MaxComponentLength < FileName->Length) + return STATUS_OBJECT_NAME_INVALID; + + DirectoryMarker.Length = DirectoryMarker.MaximumLength = FileName->Length; + DirectoryMarker.Buffer = FspAlloc(FileName->Length); + if (0 == DirectoryMarker.Buffer) + return STATUS_INSUFFICIENT_RESOURCES; + RtlCopyMemory(DirectoryMarker.Buffer, FileName->Buffer, FileName->Length); + + if (0 != FileDesc->DirectoryMarker.Buffer) + FspFree(FileDesc->DirectoryMarker.Buffer); + + FileDesc->DirectoryMarker = DirectoryMarker; return STATUS_SUCCESS; } diff --git a/tst/memfs/memfs.cpp b/tst/memfs/memfs.cpp index 8e2264c8..c32a96dc 100644 --- a/tst/memfs/memfs.cpp +++ b/tst/memfs/memfs.cpp @@ -580,58 +580,6 @@ VOID MemfsFileNodeMapEnumerateFree(MEMFS_FILE_NODE_MAP_ENUM_CONTEXT *Context) free(Context->FileNodes); } -typedef std::unordered_map MEMFS_DIR_DESC; - -static inline -NTSTATUS MemfsDirDescCreate(MEMFS_DIR_DESC **PDirDesc) -{ - *PDirDesc = 0; - try - { - *PDirDesc = new MEMFS_DIR_DESC; - return STATUS_SUCCESS; - } - catch (...) - { - return STATUS_INSUFFICIENT_RESOURCES; - } -} - -static inline -VOID MemfsDirDescDelete(MEMFS_DIR_DESC *DirDesc) -{ - delete DirDesc; -} - -static inline -VOID MemfsDirDescReset(MEMFS_DIR_DESC *DirDesc) -{ - DirDesc->clear(); -} - -static inline -PWSTR MemfsDirDescGetFileName(MEMFS_DIR_DESC *DirDesc, UINT64 Offset) -{ - MEMFS_DIR_DESC::iterator iter = DirDesc->find(Offset); - if (iter == DirDesc->end()) - return 0; - return const_cast(iter->second.c_str()); -} - -static inline -NTSTATUS MemfsDirDescInsertFileName(MEMFS_DIR_DESC *DirDesc, UINT64 Offset, PWSTR FileName) -{ - try - { - DirDesc->insert(MEMFS_DIR_DESC::value_type(Offset, FileName)); - return STATUS_SUCCESS; - } - catch (...) - { - return STATUS_INSUFFICIENT_RESOURCES; - } -} - /* * FSP_FILE_SYSTEM_INTERFACE */ @@ -745,7 +693,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, #endif MEMFS_FILE_NODE *FileNode; MEMFS_FILE_NODE *ParentNode; - MEMFS_DIR_DESC *DirDesc = 0; NTSTATUS Result; BOOLEAN Inserted; @@ -794,20 +741,9 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, } #endif - if (CreateOptions & FILE_DIRECTORY_FILE) - { - Result = MemfsDirDescCreate(&DirDesc); - if (!NT_SUCCESS(Result)) - return Result; - } - Result = MemfsFileNodeCreate(FileName, &FileNode); if (!NT_SUCCESS(Result)) - { - if (0 != DirDesc) - MemfsDirDescDelete(DirDesc); return Result; - } #if defined(MEMFS_NAMED_STREAMS) FileNode->MainFileNode = MemfsFileNodeMapGetMain(Memfs->FileNodeMap, FileName); @@ -823,8 +759,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, if (0 == FileNode->FileSecurity) { MemfsFileNodeDelete(FileNode); - if (0 != DirDesc) - MemfsDirDescDelete(DirDesc); return STATUS_INSUFFICIENT_RESOURCES; } memcpy(FileNode->FileSecurity, SecurityDescriptor, FileNode->FileSecuritySize); @@ -837,8 +771,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, if (0 == FileNode->FileData) { MemfsFileNodeDelete(FileNode); - if (0 != DirDesc) - MemfsDirDescDelete(DirDesc); return STATUS_INSUFFICIENT_RESOURCES; } } @@ -847,8 +779,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, if (!NT_SUCCESS(Result) || !Inserted) { MemfsFileNodeDelete(FileNode); - if (0 != DirDesc) - MemfsDirDescDelete(DirDesc); if (NT_SUCCESS(Result)) Result = STATUS_OBJECT_NAME_COLLISION; /* should not happen! */ return Result; @@ -869,9 +799,6 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, } #endif - /* since we now use dir descriptors to quickly retrieve dir contents, place it in UserContext2 */ - FspFileSystemGetOperationContext()->Response->Rsp.Create.Opened.UserContext2 = (UINT_PTR)DirDesc; - return STATUS_SUCCESS; } @@ -881,7 +808,6 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem, { MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS_FILE_NODE *FileNode; - MEMFS_DIR_DESC *DirDesc = 0; NTSTATUS Result; if (MEMFS_MAX_PATH <= wcslen(FileName)) @@ -895,13 +821,6 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem, return Result; } - if (0 != (FileNode->FileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - Result = MemfsDirDescCreate(&DirDesc); - if (!NT_SUCCESS(Result)) - return Result; - } - MemfsFileNodeReference(FileNode); *PFileNode = FileNode; MemfsFileNodeGetFileInfo(FileNode, FileInfo); @@ -917,9 +836,6 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem, } #endif - /* since we now use dir descriptors to quickly retrieve dir contents, place it in UserContext2 */ - FspFileSystemGetOperationContext()->Response->Rsp.Create.Opened.UserContext2 = (UINT_PTR)DirDesc; - return STATUS_SUCCESS; } @@ -1025,13 +941,8 @@ static VOID Close(FSP_FILE_SYSTEM *FileSystem, { MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0; - MEMFS_DIR_DESC *DirDesc = (MEMFS_DIR_DESC *)(UINT_PTR) - FspFileSystemGetOperationContext()->Request->Req.Close.UserContext2; MemfsFileNodeDereference(FileNode); - - if (0 != DirDesc) - MemfsDirDescDelete(DirDesc); } static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem, @@ -1394,14 +1305,11 @@ static NTSTATUS SetSecurity(FSP_FILE_SYSTEM *FileSystem, typedef struct _MEMFS_READ_DIRECTORY_CONTEXT { PVOID Buffer; - UINT64 Offset; ULONG Length; PULONG PBytesTransferred; - BOOLEAN OffsetFound; - MEMFS_DIR_DESC *DirDesc; } MEMFS_READ_DIRECTORY_CONTEXT; -static BOOLEAN AddDirInfo(MEMFS_DIR_DESC *DirDesc, MEMFS_FILE_NODE *FileNode, PWSTR FileName, +static BOOLEAN AddDirInfo(MEMFS_FILE_NODE *FileNode, PWSTR FileName, PVOID Buffer, ULONG Length, PULONG PBytesTransferred) { UINT8 DirInfoBuf[sizeof(FSP_FSCTL_DIR_INFO) + sizeof FileNode->FileName]; @@ -1414,14 +1322,11 @@ static BOOLEAN AddDirInfo(MEMFS_DIR_DESC *DirDesc, MEMFS_FILE_NODE *FileNode, PW FspPathSuffix(FileNode->FileName, &Remain, &Suffix, Root); FileName = Suffix; FspPathCombine(FileNode->FileName, Suffix); - - MemfsDirDescInsertFileName(DirDesc, FileNode->FileInfo.IndexNumber, FileName); } memset(DirInfo->Padding, 0, sizeof DirInfo->Padding); DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + wcslen(FileName) * sizeof(WCHAR)); DirInfo->FileInfo = FileNode->FileInfo; - DirInfo->NextOffset = FileNode->FileInfo.IndexNumber; memcpy(DirInfo->FileNameBuf, FileName, DirInfo->Size - sizeof(FSP_FSCTL_DIR_INFO)); return FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred); @@ -1431,39 +1336,24 @@ static BOOLEAN ReadDirectoryEnumFn(MEMFS_FILE_NODE *FileNode, PVOID Context0) { MEMFS_READ_DIRECTORY_CONTEXT *Context = (MEMFS_READ_DIRECTORY_CONTEXT *)Context0; - if (0 != Context->Offset && !Context->OffsetFound) - { - Context->OffsetFound = FileNode->FileInfo.IndexNumber == Context->Offset; - return TRUE; - } - - return AddDirInfo(Context->DirDesc, FileNode, 0, + return AddDirInfo(FileNode, 0, Context->Buffer, Context->Length, Context->PBytesTransferred); } static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem, - PVOID FileNode0, PVOID Buffer, UINT64 Offset, ULONG Length, - PWSTR Pattern, + PVOID FileNode0, PVOID Buffer, ULONG Length, + PWSTR Pattern, PWSTR Marker, PULONG PBytesTransferred) { MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0; - MEMFS_DIR_DESC *DirDesc = (MEMFS_DIR_DESC *)(UINT_PTR) - FspFileSystemGetOperationContext()->Request->Req.QueryDirectory.UserContext2; MEMFS_FILE_NODE *ParentNode; MEMFS_READ_DIRECTORY_CONTEXT Context; - PWSTR PrevFileName = 0; NTSTATUS Result; Context.Buffer = Buffer; - Context.Offset = Offset; Context.Length = Length; Context.PBytesTransferred = PBytesTransferred; - Context.OffsetFound = FALSE; - Context.DirDesc = DirDesc; - - if (0 == Offset) - MemfsDirDescReset(DirDesc); if (L'\0' != FileNode->FileName[1]) { @@ -1473,25 +1363,20 @@ static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem, if (0 == ParentNode) return Result; - if (0 == Offset) - if (!AddDirInfo(DirDesc, FileNode, L".", Buffer, Length, PBytesTransferred)) - return STATUS_SUCCESS; - if (0 == Offset || FileNode->FileInfo.IndexNumber == Offset) + if (0 == Marker) { - Context.OffsetFound = FileNode->FileInfo.IndexNumber == Context.Offset; - - if (!AddDirInfo(DirDesc, ParentNode, L"..", Buffer, Length, PBytesTransferred)) + if (!AddDirInfo(FileNode, L".", Buffer, Length, PBytesTransferred)) return STATUS_SUCCESS; } + if (0 == Marker || (L'.' == Marker[0] && L'\0' == Marker[1])) + { + if (!AddDirInfo(ParentNode, L"..", Buffer, Length, PBytesTransferred)) + return STATUS_SUCCESS; + Marker = 0; + } } - if (0 != Context.Offset && !Context.OffsetFound) - { - PrevFileName = MemfsDirDescGetFileName(DirDesc, Offset); - Context.OffsetFound = 0 != PrevFileName; - } - - if (MemfsFileNodeMapEnumerateChildren(Memfs->FileNodeMap, FileNode, PrevFileName, + if (MemfsFileNodeMapEnumerateChildren(Memfs->FileNodeMap, FileNode, Marker, ReadDirectoryEnumFn, &Context)) FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred);