From 5110b3c5a171dfde7881ef33a6074a9b170ac00a Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 30 Oct 2019 16:40:48 -0700 Subject: [PATCH] sys: dirctl: support directory marker as FUSE style next offset --- inc/winfsp/fsctl.h | 13 +++++++---- src/sys/dirctl.c | 56 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h index 45f1e40d..daa33418 100644 --- a/inc/winfsp/fsctl.h +++ b/inc/winfsp/fsctl.h @@ -96,7 +96,7 @@ FSP_FSCTL_STATIC_ASSERT(FSP_FSCTL_VOLUME_NAME_SIZEMAX <= 260 * sizeof(WCHAR), /* marshalling */ #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 { FspFsctlTransactReservedKind = 0, @@ -175,7 +175,8 @@ enum UINT32 AllowOpenInKernelMode:1; /* allow kernel mode to open files when possible */\ UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\ 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 FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)]; #define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\ @@ -242,8 +243,12 @@ typedef struct { UINT16 Size; FSP_FSCTL_FILE_INFO FileInfo; - UINT8 Padding[24]; - /* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */ + union + { + UINT64 NextOffset; + UINT8 Padding[24]; + /* make struct as big as FILE_ID_BOTH_DIR_INFORMATION; allows for in-place copying */ + } DUMMYUNIONNAME; WCHAR FileNameBuf[]; } FSP_FSCTL_DIR_INFO; FSP_FSCTL_STATIC_ASSERT(104 == sizeof(FSP_FSCTL_DIR_INFO), diff --git a/src/sys/dirctl.c b/src/sys/dirctl.c index 54e21f6e..a2b668c0 100644 --- a/src/sys/dirctl.c +++ b/src/sys/dirctl.c @@ -24,6 +24,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive, PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut, + PUINT64 DirectoryMarkerAsNextOffset, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, BOOLEAN ReturnEaSize, FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize, @@ -88,6 +89,7 @@ enum static NTSTATUS FspFsvolQueryDirectoryCopy( PUNICODE_STRING DirectoryPattern, BOOLEAN CaseInsensitive, PUNICODE_STRING DirectoryMarker, PUNICODE_STRING DirectoryMarkerOut, + PUINT64 DirectoryMarkerAsNextOffset, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, BOOLEAN ReturnEaSize, FSP_FSCTL_DIR_INFO **PDirInfo, ULONG DirInfoSize, @@ -130,6 +132,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( PVOID PrevDestBuf = 0; ULONG BaseInfoLen, CopyLength; UNICODE_STRING FileName; + UINT64 DirectoryNextOffset; *PDestLen = 0; @@ -176,12 +179,21 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( FileName.MaximumLength = (USHORT)(DirInfoSize - sizeof(FSP_FSCTL_DIR_INFO)); FileName.Buffer = DirInfo->FileNameBuf; + DirectoryNextOffset = DirInfo->NextOffset; + if (0 != DirectoryMarker && 0 != DirectoryMarker->Buffer && !DirectoryMarkerFound) { - DirectoryMarkerFound = 0 == FspFileNameCompare( - &FileName, DirectoryMarker, CaseInsensitive, 0); - continue; + if (0 == DirectoryMarkerAsNextOffset) + { + 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 */ @@ -272,8 +284,16 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( break; } - DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = FileName.Length; - DirectoryMarkerOut->Buffer = (PVOID)((PUINT8)DestBuf + BaseInfoLen); + if (0 == DirectoryMarkerAsNextOffset) + { + DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = FileName.Length; + DirectoryMarkerOut->Buffer = (PVOID)((PUINT8)DestBuf + BaseInfoLen); + } + else + { + DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = sizeof(UINT64); + DirectoryMarkerOut->Buffer = (PVOID)DirectoryMarkerAsNextOffset; + } DestBuf = (PVOID)((PUINT8)DestBuf + FSP_FSCTL_ALIGN_UP(BaseInfoLen + CopyLength, sizeof(LONGLONG))); @@ -283,7 +303,15 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( Loop = FALSE; } else - *DirectoryMarkerOut = FileName; + { + if (0 == DirectoryMarkerAsNextOffset) + *DirectoryMarkerOut = FileName; + else + { + DirectoryMarkerOut->Length = DirectoryMarkerOut->MaximumLength = sizeof(UINT64); + DirectoryMarkerOut->Buffer = (PVOID)DirectoryMarkerAsNextOffset; + } + } } } except (EXCEPTION_EXECUTE_HANDLER) @@ -323,9 +351,12 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache( FileDesc->DirInfo = FileNode->NonPaged->DirInfo; NTSTATUS Result; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = + FspFsvolDeviceExtension(FileNode->FsvolDeviceObject); BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive; PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern; UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker; + UINT64 DirectoryMarkerAsNextOffset = 0; PUINT8 DirInfoBgn = (PUINT8)DirInfo; PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize; @@ -334,8 +365,10 @@ static NTSTATUS FspFsvolQueryDirectoryCopyCache( Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive, 0 != FileDesc->DirInfoCacheHint ? 0 : &FileDesc->DirectoryMarker, &DirectoryMarker, + FsvolDeviceExtension->VolumeParams.DirectoryMarkerAsNextOffset ? + &DirectoryMarkerAsNextOffset : 0, FileInformationClass, ReturnSingleEntry, - !!FspFsvolDeviceExtension(FileNode->FsvolDeviceObject)->VolumeParams.ExtendedAttributes, + !!FsvolDeviceExtension->VolumeParams.ExtendedAttributes, &DirInfo, DirInfoSize, DestBuf, PDestLen); @@ -366,10 +399,13 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace( PAGED_CODE(); NTSTATUS Result; + FSP_FILE_NODE *FileNode = FileDesc->FileNode; + FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = + FspFsvolDeviceExtension(FileNode->FsvolDeviceObject); BOOLEAN CaseInsensitive = !FileDesc->CaseSensitive; PUNICODE_STRING DirectoryPattern = &FileDesc->DirectoryPattern; UNICODE_STRING DirectoryMarker = FileDesc->DirectoryMarker; - FSP_FILE_NODE *FileNode = FileDesc->FileNode; + UINT64 DirectoryMarkerAsNextOffset = 0; FSP_FSCTL_STATIC_ASSERT( FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) >= @@ -378,8 +414,10 @@ static NTSTATUS FspFsvolQueryDirectoryCopyInPlace( Result = FspFsvolQueryDirectoryCopy(DirectoryPattern, CaseInsensitive, 0, &DirectoryMarker, + FsvolDeviceExtension->VolumeParams.DirectoryMarkerAsNextOffset ? + &DirectoryMarkerAsNextOffset : 0, FileInformationClass, ReturnSingleEntry, - !!FspFsvolDeviceExtension(FileNode->FsvolDeviceObject)->VolumeParams.ExtendedAttributes, + !!FsvolDeviceExtension->VolumeParams.ExtendedAttributes, &DirInfo, DirInfoSize, DestBuf, PDestLen);