From 096b2dabdeb744bcbcc31d93bbcb6aa9e759dc7d Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 14 Oct 2016 14:06:41 -0700 Subject: [PATCH] sys: refactor util.c into strutil.c; introduce FspIsNameInExpression to wrap FsRtlIsNameInExpression --- build/VStudio/winfsp_sys.vcxproj | 1 + build/VStudio/winfsp_sys.vcxproj.filters | 3 + src/sys/dirctl.c | 12 +- src/sys/driver.h | 14 +- src/sys/strutil.c | 223 +++++++++++++++++++++++ src/sys/util.c | 174 ------------------ 6 files changed, 248 insertions(+), 179 deletions(-) create mode 100644 src/sys/strutil.c diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj index c7157a25..a65e5b5d 100644 --- a/build/VStudio/winfsp_sys.vcxproj +++ b/build/VStudio/winfsp_sys.vcxproj @@ -176,6 +176,7 @@ + diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index 66204d64..55f21a62 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -92,6 +92,9 @@ Source + + Source + diff --git a/src/sys/dirctl.c b/src/sys/dirctl.c index d0d9f5c0..93c06c4d 100644 --- a/src/sys/dirctl.c +++ b/src/sys/dirctl.c @@ -118,7 +118,7 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( PAGED_CODE(); NTSTATUS Result = STATUS_SUCCESS; - BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer; + BOOLEAN MatchAll = FspFileDescDirectoryPatternMatchAll == DirectoryPattern->Buffer, Match; BOOLEAN Loop = TRUE, DirectoryOffsetFound = FALSE; FSP_FSCTL_DIR_INFO *DirInfo = *PDirInfo; PUINT8 DirInfoEnd = (PUINT8)DirInfo + DirInfoSize; @@ -182,7 +182,15 @@ static NTSTATUS FspFsvolQueryDirectoryCopy( /* CopyLength is the same as FileName.Length except on STATUS_BUFFER_OVERFLOW */ CopyLength = FileName.Length; - if (MatchAll || FsRtlIsNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0)) + Match = MatchAll; + if (!Match) + { + Result = FspIsNameInExpression(DirectoryPattern, &FileName, CaseInsensitive, 0, &Match); + if (!NT_SUCCESS(Result)) + return Result; + } + + if (Match) { if ((PUINT8)DestBuf + BaseInfoLen + CopyLength > DestBufEnd) { diff --git a/src/sys/driver.h b/src/sys/driver.h index 956b8cba..8e5e1033 100644 --- a/src/sys/driver.h +++ b/src/sys/driver.h @@ -428,17 +428,25 @@ BOOLEAN FspExpirationTimeValid2(UINT64 ExpirationTime, UINT64 CurrentTime) return CurrentTime < ExpirationTime; } -/* utility */ +/* string utility */ enum { FspUnicodePathStreamTypeNone = 0, FspUnicodePathStreamTypeData = 1, }; -PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag); -PVOID FspAllocateIrpMustSucceed(CCHAR StackSize); BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType); BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern); VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); +NTSTATUS FspIsNameInExpression( + PUNICODE_STRING Expression, + PUNICODE_STRING Name, + BOOLEAN IgnoreCase, + PWCH UpcaseTable, + PBOOLEAN PResult); + +/* utility */ +PVOID FspAllocatePoolMustSucceed(POOL_TYPE PoolType, SIZE_T Size, ULONG Tag); +PVOID FspAllocateIrpMustSucceed(CCHAR StackSize); NTSTATUS FspCreateGuid(GUID *Guid); NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess, PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject); diff --git a/src/sys/strutil.c b/src/sys/strutil.c new file mode 100644 index 00000000..901813a6 --- /dev/null +++ b/src/sys/strutil.c @@ -0,0 +1,223 @@ +/** + * @file sys/strutil.c + * + * @copyright 2015-2016 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include + +BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType); +BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern); +VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); +NTSTATUS FspIsNameInExpression( + PUNICODE_STRING Expression, + PUNICODE_STRING Name, + BOOLEAN IgnoreCase, + PWCH UpcaseTable, + PBOOLEAN PResult); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, FspUnicodePathIsValid) +#pragma alloc_text(PAGE, FspUnicodePathIsValidPattern) +#pragma alloc_text(PAGE, FspUnicodePathSuffix) +#pragma alloc_text(PAGE, FspIsNameInExpression) +#endif + +BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType) +{ + PAGED_CODE(); + + /* if StreamPart is not NULL, StreamType must also be not NULL */ + ASSERT(0 == StreamPart || 0 != StreamType); + + if (0 != Path->Length % sizeof(WCHAR)) + return FALSE; + + PWSTR PathBgn, PathEnd, PathPtr, StreamTypeStr = 0; + UCHAR Flags = FSRTL_NTFS_LEGAL; + ULONG Colons = 0; + WCHAR Char; + + PathBgn = Path->Buffer; + PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length); + PathPtr = PathBgn; + + while (PathEnd > PathPtr) + { + Char = *PathPtr; + + if (L'\\' == Char) + { + /* stream names can only appear as the last path component */ + if (0 < Colons) + return FALSE; + + PathPtr++; + + /* don't like multiple backslashes */ + if (PathEnd > PathPtr && L'\\' == *PathPtr) + return FALSE; + } + else if (L':' == Char) + { + if (0 == StreamPart) + return FALSE; + + /* + * Where are the docs on legal stream names? + */ + + /* stream characters now allowed */ + Flags = FSRTL_NTFS_STREAM_LEGAL; + + PathPtr++; + Colons++; + + if (1 == Colons) + { + /* first time through: set up StreamPart */ + StreamPart->Length = StreamPart->MaximumLength = (USHORT) + ((PUINT8)PathEnd - (PUINT8)PathPtr); + StreamPart->Buffer = PathPtr; + } + else if (2 == Colons) + { + /* second time through: fix StreamPart length to not include 2nd colon */ + StreamPart->Length = (USHORT) + ((PUINT8)PathPtr - (PUINT8)StreamPart->Buffer - sizeof(WCHAR)); + + StreamTypeStr = PathPtr; + } + } + else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, FALSE, Flags)) + return FALSE; + else + PathPtr++; + } + + /* if we had no colons the path is valid */ + if (0 == Colons) + return TRUE; + + ASSERT(0 != StreamPart && 0 != StreamType); + + *StreamType = FspUnicodePathStreamTypeNone; + + /* if we had no stream type the path is valid if there was an actual stream name */ + if (0 == StreamTypeStr) + return 0 != StreamPart->Length; + + /* if we had a stream type the path is valid if the stream type was "$DATA" only */ + if (StreamTypeStr + 5 == PathEnd && + L'$' == StreamTypeStr[0] && + L'D' == StreamTypeStr[1] && + L'A' == StreamTypeStr[2] && + L'T' == StreamTypeStr[3] && + L'A' == StreamTypeStr[4]) + { + *StreamType = FspUnicodePathStreamTypeData; + return TRUE; + } + + return FALSE; +} + +BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Path) +{ + PAGED_CODE(); + + if (0 != Path->Length % sizeof(WCHAR)) + return FALSE; + + PWSTR PathBgn, PathEnd, PathPtr; + WCHAR Char; + + PathBgn = Path->Buffer; + PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length); + PathPtr = PathBgn; + + while (PathEnd > PathPtr) + { + Char = *PathPtr; + + /* + * A pattern is allowed to have wildcards. It cannot consist of multiple + * path components (have a backslash) and it cannot reference a stream (have + * a colon). + */ + + if (L'\\' == Char) + return FALSE; + else if (L':' == Char) + return FALSE; + else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, TRUE, FSRTL_NTFS_LEGAL)) + return FALSE; + else + PathPtr++; + } + + return TRUE; +} + +VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix) +{ + PAGED_CODE(); + + PWSTR PathBgn, PathEnd, PathPtr, RemainEnd, SuffixBgn; + + PathBgn = Path->Buffer; + PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length); + PathPtr = PathBgn; + + RemainEnd = PathEnd; + SuffixBgn = PathEnd; + + while (PathEnd > PathPtr) + if (L'\\' == *PathPtr) + { + RemainEnd = PathPtr++; + for (; PathEnd > PathPtr && L'\\' == *PathPtr; PathPtr++) + ; + SuffixBgn = PathPtr; + } + else + PathPtr++; + + Remain->Length = Remain->MaximumLength = (USHORT)((PUINT8)RemainEnd - (PUINT8)PathBgn); + Remain->Buffer = PathBgn; + if (0 == Remain->Length && PathBgn < PathEnd && L'\\' == *PathBgn) + Remain->Length = Remain->MaximumLength = sizeof(WCHAR); + Suffix->Length = Suffix->MaximumLength = (USHORT)((PUINT8)PathEnd - (PUINT8)SuffixBgn); + Suffix->Buffer = SuffixBgn; +} + +NTSTATUS FspIsNameInExpression( + PUNICODE_STRING Expression, + PUNICODE_STRING Name, + BOOLEAN IgnoreCase, + PWCH UpcaseTable, + PBOOLEAN PResult) +{ + PAGED_CODE(); + + try + { + *PResult = FsRtlIsNameInExpression(Expression, Name, IgnoreCase, UpcaseTable); + return STATUS_SUCCESS; + } + except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } +} diff --git a/src/sys/util.c b/src/sys/util.c index 13735892..9b28cae2 100644 --- a/src/sys/util.c +++ b/src/sys/util.c @@ -17,9 +17,6 @@ #include -BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType); -BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Pattern); -VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix); NTSTATUS FspCreateGuid(GUID *Guid); NTSTATUS FspGetDeviceObjectPointer(PUNICODE_STRING ObjectName, ACCESS_MASK DesiredAccess, PULONG PFileNameIndex, PFILE_OBJECT *PFileObject, PDEVICE_OBJECT *PDeviceObject); @@ -88,9 +85,6 @@ PVOID FspIrpHookContext(PVOID Context); NTSTATUS FspIrpHookNext(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context); #ifdef ALLOC_PRAGMA -#pragma alloc_text(PAGE, FspUnicodePathIsValid) -#pragma alloc_text(PAGE, FspUnicodePathIsValidPattern) -#pragma alloc_text(PAGE, FspUnicodePathSuffix) #pragma alloc_text(PAGE, FspCreateGuid) #pragma alloc_text(PAGE, FspGetDeviceObjectPointer) #pragma alloc_text(PAGE, FspSendSetInformationIrp) @@ -171,174 +165,6 @@ PVOID FspAllocateIrpMustSucceed(CCHAR StackSize) } } -BOOLEAN FspUnicodePathIsValid(PUNICODE_STRING Path, PUNICODE_STRING StreamPart, PULONG StreamType) -{ - PAGED_CODE(); - - /* if StreamPart is not NULL, StreamType must also be not NULL */ - ASSERT(0 == StreamPart || 0 != StreamType); - - if (0 != Path->Length % sizeof(WCHAR)) - return FALSE; - - PWSTR PathBgn, PathEnd, PathPtr, StreamTypeStr = 0; - UCHAR Flags = FSRTL_NTFS_LEGAL; - ULONG Colons = 0; - WCHAR Char; - - PathBgn = Path->Buffer; - PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length); - PathPtr = PathBgn; - - while (PathEnd > PathPtr) - { - Char = *PathPtr; - - if (L'\\' == Char) - { - /* stream names can only appear as the last path component */ - if (0 < Colons) - return FALSE; - - PathPtr++; - - /* don't like multiple backslashes */ - if (PathEnd > PathPtr && L'\\' == *PathPtr) - return FALSE; - } - else if (L':' == Char) - { - if (0 == StreamPart) - return FALSE; - - /* - * Where are the docs on legal stream names? - */ - - /* stream characters now allowed */ - Flags = FSRTL_NTFS_STREAM_LEGAL; - - PathPtr++; - Colons++; - - if (1 == Colons) - { - /* first time through: set up StreamPart */ - StreamPart->Length = StreamPart->MaximumLength = (USHORT) - ((PUINT8)PathEnd - (PUINT8)PathPtr); - StreamPart->Buffer = PathPtr; - } - else if (2 == Colons) - { - /* second time through: fix StreamPart length to not include 2nd colon */ - StreamPart->Length = (USHORT) - ((PUINT8)PathPtr - (PUINT8)StreamPart->Buffer - sizeof(WCHAR)); - - StreamTypeStr = PathPtr; - } - } - else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, FALSE, Flags)) - return FALSE; - else - PathPtr++; - } - - /* if we had no colons the path is valid */ - if (0 == Colons) - return TRUE; - - ASSERT(0 != StreamPart && 0 != StreamType); - - *StreamType = FspUnicodePathStreamTypeNone; - - /* if we had no stream type the path is valid if there was an actual stream name */ - if (0 == StreamTypeStr) - return 0 != StreamPart->Length; - - /* if we had a stream type the path is valid if the stream type was "$DATA" only */ - if (StreamTypeStr + 5 == PathEnd && - L'$' == StreamTypeStr[0] && - L'D' == StreamTypeStr[1] && - L'A' == StreamTypeStr[2] && - L'T' == StreamTypeStr[3] && - L'A' == StreamTypeStr[4]) - { - *StreamType = FspUnicodePathStreamTypeData; - return TRUE; - } - - return FALSE; -} - -BOOLEAN FspUnicodePathIsValidPattern(PUNICODE_STRING Path) -{ - PAGED_CODE(); - - if (0 != Path->Length % sizeof(WCHAR)) - return FALSE; - - PWSTR PathBgn, PathEnd, PathPtr; - WCHAR Char; - - PathBgn = Path->Buffer; - PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length); - PathPtr = PathBgn; - - while (PathEnd > PathPtr) - { - Char = *PathPtr; - - /* - * A pattern is allowed to have wildcards. It cannot consist of multiple - * path components (have a backslash) and it cannot reference a stream (have - * a colon). - */ - - if (L'\\' == Char) - return FALSE; - else if (L':' == Char) - return FALSE; - else if (0x80 > Char && !FsRtlTestAnsiCharacter(Char, TRUE, TRUE, FSRTL_NTFS_LEGAL)) - return FALSE; - else - PathPtr++; - } - - return TRUE; -} - -VOID FspUnicodePathSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix) -{ - PAGED_CODE(); - - PWSTR PathBgn, PathEnd, PathPtr, RemainEnd, SuffixBgn; - - PathBgn = Path->Buffer; - PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length); - PathPtr = PathBgn; - - RemainEnd = PathEnd; - SuffixBgn = PathEnd; - - while (PathEnd > PathPtr) - if (L'\\' == *PathPtr) - { - RemainEnd = PathPtr++; - for (; PathEnd > PathPtr && L'\\' == *PathPtr; PathPtr++) - ; - SuffixBgn = PathPtr; - } - else - PathPtr++; - - Remain->Length = Remain->MaximumLength = (USHORT)((PUINT8)RemainEnd - (PUINT8)PathBgn); - Remain->Buffer = PathBgn; - if (0 == Remain->Length && PathBgn < PathEnd && L'\\' == *PathBgn) - Remain->Length = Remain->MaximumLength = sizeof(WCHAR); - Suffix->Length = Suffix->MaximumLength = (USHORT)((PUINT8)PathEnd - (PUINT8)SuffixBgn); - Suffix->Buffer = SuffixBgn; -} - NTSTATUS FspCreateGuid(GUID *Guid) { PAGED_CODE();