mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
281 lines
7.7 KiB
C
281 lines
7.7 KiB
C
/**
|
|
* @file sys/name.c
|
|
*
|
|
* @copyright 2015-2019 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 software
|
|
* in accordance with the commercial license agreement provided in
|
|
* conjunction with the software. The terms and conditions of any such
|
|
* commercial license agreement shall govern, supersede, and render
|
|
* ineffective any application of the GPLv3 license to this software,
|
|
* notwithstanding of any reference thereto in the software or
|
|
* associated repository.
|
|
*/
|
|
|
|
#include <sys/driver.h>
|
|
|
|
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, ULONG MaxComponentLength,
|
|
PUNICODE_STRING StreamPart, PULONG StreamType);
|
|
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Pattern, ULONG MaxComponentLength);
|
|
BOOLEAN FspEaNameIsValid(PSTRING Name);
|
|
VOID FspFileNameSuffix(PUNICODE_STRING Path, PUNICODE_STRING Remain, PUNICODE_STRING Suffix);
|
|
NTSTATUS FspFileNameInExpression(
|
|
PUNICODE_STRING Expression,
|
|
PUNICODE_STRING Name,
|
|
BOOLEAN IgnoreCase,
|
|
PWCH UpcaseTable,
|
|
PBOOLEAN PResult);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, FspFileNameIsValid)
|
|
#pragma alloc_text(PAGE, FspFileNameIsValidPattern)
|
|
#pragma alloc_text(PAGE, FspEaNameIsValid)
|
|
#pragma alloc_text(PAGE, FspFileNameSuffix)
|
|
#pragma alloc_text(PAGE, FspFileNameInExpression)
|
|
#endif
|
|
|
|
BOOLEAN FspFileNameIsValid(PUNICODE_STRING Path, ULONG MaxComponentLength,
|
|
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 || 0 != Path->Length % sizeof(WCHAR))
|
|
return FALSE;
|
|
|
|
PWSTR PathBgn, PathEnd, PathPtr, ComponentPtr, StreamTypeStr = 0;
|
|
UCHAR Flags = FSRTL_NTFS_LEGAL;
|
|
ULONG Colons = 0;
|
|
WCHAR Char;
|
|
|
|
PathBgn = Path->Buffer;
|
|
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
|
|
PathPtr = PathBgn;
|
|
ComponentPtr = PathPtr;
|
|
|
|
while (PathEnd > PathPtr)
|
|
{
|
|
Char = *PathPtr;
|
|
|
|
if (L'\\' == Char)
|
|
{
|
|
/* stream names can only appear as the last path component */
|
|
if (0 < Colons)
|
|
return FALSE;
|
|
|
|
/* path component cannot be longer than MaxComponentLength */
|
|
if ((ULONG)(PathPtr - ComponentPtr) > MaxComponentLength)
|
|
return FALSE;
|
|
|
|
PathPtr++;
|
|
ComponentPtr = 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++;
|
|
}
|
|
|
|
/* path component cannot be longer than MaxComponentLength */
|
|
if ((ULONG)(PathPtr - ComponentPtr) > MaxComponentLength)
|
|
return FALSE;
|
|
|
|
/* if we had no colons the path is valid */
|
|
if (0 == Colons)
|
|
return TRUE;
|
|
|
|
ASSERT(0 != StreamPart && 0 != StreamType);
|
|
|
|
*StreamType = FspFileNameStreamTypeNone;
|
|
|
|
/* 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] | 0x20) &&
|
|
L'a' == (StreamTypeStr[2] | 0x20) &&
|
|
L't' == (StreamTypeStr[3] | 0x20) &&
|
|
L'a' == (StreamTypeStr[4] | 0x20))
|
|
{
|
|
*StreamType = FspFileNameStreamTypeData;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN FspFileNameIsValidPattern(PUNICODE_STRING Path, ULONG MaxComponentLength)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (0 != Path->Length % sizeof(WCHAR))
|
|
return FALSE;
|
|
|
|
PWSTR PathBgn, PathEnd, PathPtr, ComponentPtr;
|
|
WCHAR Char;
|
|
|
|
PathBgn = Path->Buffer;
|
|
PathEnd = (PWSTR)((PUINT8)PathBgn + Path->Length);
|
|
PathPtr = PathBgn;
|
|
ComponentPtr = PathPtr;
|
|
|
|
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++;
|
|
}
|
|
|
|
/* path component cannot be longer than MaxComponentLength */
|
|
if ((ULONG)(PathPtr - ComponentPtr) > MaxComponentLength)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN FspEaNameIsValid(PSTRING Name)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* see FastFat's FatIsEaNameValid */
|
|
|
|
if (0 == Name->Length || Name->Length > 254)
|
|
return FALSE;
|
|
|
|
PSTR NameEnd, NamePtr;
|
|
CHAR Char;
|
|
|
|
NamePtr = Name->Buffer;
|
|
NameEnd = NamePtr + Name->Length;
|
|
|
|
while (NameEnd > NamePtr)
|
|
{
|
|
Char = *NamePtr;
|
|
|
|
if (FsRtlIsLeadDbcsCharacter(Char))
|
|
NamePtr++;
|
|
else
|
|
if (!FsRtlIsAnsiCharacterLegalFat(Char, FALSE))
|
|
return FALSE;
|
|
|
|
NamePtr++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID FspFileNameSuffix(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 FspFileNameInExpression(
|
|
PUNICODE_STRING Expression,
|
|
PUNICODE_STRING Name,
|
|
BOOLEAN IgnoreCase,
|
|
PWCH UpcaseTable,
|
|
PBOOLEAN PResult)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* we do not support non-NULL UpcaseTable yet */
|
|
ASSERT(0 == UpcaseTable);
|
|
|
|
try
|
|
{
|
|
*PResult = FsRtlIsNameInExpression(Expression, Name, IgnoreCase, UpcaseTable);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return GetExceptionCode();
|
|
}
|
|
}
|