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();