From dcf3d612bcebdc3054f2897a93fad1ad576587dc Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 6 Sep 2018 16:40:27 -0700 Subject: [PATCH] sys: create: FspFsvolCreate Fix file name case after crossing a reparse point as per http://online.osr.com/ShowThread.cfm?link=287522 --- src/sys/create.c | 61 +++++++++++++++++++++++++++++++++++++++++++++ tools/run-tests.bat | 12 +++++++++ 2 files changed, 73 insertions(+) diff --git a/src/sys/create.c b/src/sys/create.c index 4395b54f..f46f148d 100644 --- a/src/sys/create.c +++ b/src/sys/create.c @@ -69,6 +69,16 @@ FSP_DRIVER_DISPATCH FspCreate; #pragma alloc_text(PAGE, FspCreate) #endif +/* + * FSP_CREATE_REPARSE_POINT_ECP + * + * Define this macro to include code to fix file name case after crossing + * a reparse point as per http://online.osr.com/ShowThread.cfm?link=287522. + * Fixing this problem requires undocumented information; for this reason + * this fix is EXPERIMENTAL. + */ +#define FSP_CREATE_REPARSE_POINT_ECP + #define PREFIXW L"" FSP_FSCTL_VOLUME_PARAMS_PREFIX #define PREFIXW_SIZE (sizeof PREFIXW - sizeof(WCHAR)) @@ -140,6 +150,12 @@ static NTSTATUS FspFsvolCreate( * of the main file for a stream. In this case this is a reentrant open * and we should be careful not to try to acquire the rename resource, * which is already acquired (otherwise DEADLOCK). + * + * - To determine whether this is an open after crossing a reparse point + * (e.g. when the file system is mounted as a directory). Unfortunately + * Windows does not preserve file name case in this case and sends us + * UPPERCASE file names, which results in all kinds of problems, esp. + * for case-sensitive file systems. */ ExtraCreateParameters = 0; Result = FsRtlGetEcpListFromIrp(Irp, &ExtraCreateParameters); @@ -151,6 +167,51 @@ static NTSTATUS FspFsvolCreate( &FspMainFileOpenEcpGuid, &ExtraCreateParameter, 0)) && 0 != ExtraCreateParameter && !FsRtlIsEcpFromUserMode(ExtraCreateParameter); + +#if defined(FSP_CREATE_REPARSE_POINT_ECP) + // {73d5118a-88ba-439f-92f4-46d38952d250} + static const GUID FspReparsePointEcpGuid = + { 0x73d5118a, 0x88ba, 0x439f, { 0x92, 0xf4, 0x46, 0xd3, 0x89, 0x52, 0xd2, 0x50 } }; + typedef struct _REPARSE_POINT_ECP + { + USHORT UnparsedNameLength; + USHORT Flags; + USHORT DeviceNameLength; + PVOID Reserved; + UNICODE_STRING Name; + } REPARSE_POINT_ECP; + REPARSE_POINT_ECP *ReparsePointEcp; + + ExtraCreateParameter = 0; + ReparsePointEcp = + NT_SUCCESS(FsRtlFindExtraCreateParameter(ExtraCreateParameters, + &FspReparsePointEcpGuid, &ExtraCreateParameter, 0)) && + 0 != ExtraCreateParameter && + !FsRtlIsEcpFromUserMode(ExtraCreateParameter) ? + ExtraCreateParameter : 0; + if (0 != ReparsePointEcp) + { + //DEBUGLOG("%hu %wZ", ReparsePointEcp->UnparsedNameLength, ReparsePointEcp->Name); + + UNICODE_STRING FileName = IrpSp->FileObject->FileName; + if (0 != ReparsePointEcp->UnparsedNameLength && + FileName.Length == ReparsePointEcp->UnparsedNameLength && + ReparsePointEcp->Name.Length > ReparsePointEcp->UnparsedNameLength) + { + /* + * If the ReparsePointEcp name and our file name differ only in case, + * go ahead and overwrite our file name. + */ + + UNICODE_STRING UnparsedName; + UnparsedName.Length = UnparsedName.MaximumLength = ReparsePointEcp->UnparsedNameLength; + UnparsedName.Buffer = (PWCH)((UINT8 *)ReparsePointEcp->Name.Buffer + + (ReparsePointEcp->Name.Length - UnparsedName.Length)); + if (0 == FspFileNameCompare(&UnparsedName, &FileName, TRUE, 0)) + RtlMoveMemory(FileName.Buffer, UnparsedName.Buffer, UnparsedName.Length); + } + } +#endif } if (!MainFileOpen) diff --git a/tools/run-tests.bat b/tools/run-tests.bat index 5a929905..748d314b 100755 --- a/tools/run-tests.bat +++ b/tools/run-tests.bat @@ -34,6 +34,7 @@ set dfl_tests=^ winfsp-tests-x64-flushpurge ^ winfsp-tests-x64-mountpoint-drive ^ winfsp-tests-x64-mountpoint-dir ^ + winfsp-tests-x64-mountpoint-dir-case-sensitive ^ winfsp-tests-x64-no-traverse ^ winfsp-tests-x64-oplock ^ winfsp-tests-x64-external ^ @@ -52,6 +53,7 @@ set dfl_tests=^ winfsp-tests-x86-flushpurge ^ winfsp-tests-x86-mountpoint-drive ^ winfsp-tests-x86-mountpoint-dir ^ + winfsp-tests-x86-mountpoint-dir-case-sensitive ^ winfsp-tests-x86-no-traverse ^ winfsp-tests-x86-oplock ^ winfsp-tests-x86-external ^ @@ -192,6 +194,11 @@ winfsp-tests-x64 --mountpoint=mymnt --case-insensitive if !ERRORLEVEL! neq 0 goto fail exit /b 0 +:winfsp-tests-x64-mountpoint-dir-case-sensitive +winfsp-tests-x64 --mountpoint=mymnt +if !ERRORLEVEL! neq 0 goto fail +exit /b 0 + :winfsp-tests-x64-no-traverse winfsp-tests-x64 --no-traverse if !ERRORLEVEL! neq 0 goto fail @@ -227,6 +234,11 @@ winfsp-tests-x86 --mountpoint=mymnt --case-insensitive if !ERRORLEVEL! neq 0 goto fail exit /b 0 +:winfsp-tests-x86-mountpoint-dir-case-sensitive +winfsp-tests-x86 --mountpoint=mymnt +if !ERRORLEVEL! neq 0 goto fail +exit /b 0 + :winfsp-tests-x86-no-traverse winfsp-tests-x86 --no-traverse if !ERRORLEVEL! neq 0 goto fail