reactos/drivers/filesystems/udfs/namesup.cpp

298 lines
7.4 KiB
C++

////////////////////////////////////////////////////////////////////
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
// All rights reserved
// This file was released under the GPLv2 on June 2015.
////////////////////////////////////////////////////////////////////
/*
Module:
Namesup.cpp
Abstract: FileName support routines
*/
#include "udffs.h"
// '\dfdf\aaa\ffg' --> '\aaa\ffg'
// '\aaa\ffg' --> '\ffg'
PWCHAR
__fastcall
UDFDissectName(
IN PWCHAR Buffer,
OUT PUSHORT Length
)
{
USHORT i;
#if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
PWCHAR retval;
__asm push ebx
__asm push ecx
__asm mov ebx,Buffer
__asm xor ecx,ecx
Remove_leading_slash:
__asm cmp [word ptr ebx],L'\\'
__asm jne No_IncPointer
__asm add ebx,2
__asm jmp Remove_leading_slash
No_IncPointer:
__asm cmp [word ptr ebx],L':'
__asm jne Scan_1
__asm add ebx,2
__asm inc ecx
__asm jmp EO_Dissect
Scan_1:
__asm mov ax,[word ptr ebx]
__asm cmp ax,L'\\'
__asm je EO_Dissect
__asm or ax,ax
__asm jz EO_Dissect
__asm cmp ax,L':'
__asm jne Cont_scan
__asm or ecx,ecx
__asm jnz EO_Dissect
Cont_scan:
__asm inc ecx
__asm add ebx,2
__asm jmp Scan_1
EO_Dissect:
__asm mov retval,ebx
__asm mov i,cx
__asm pop ecx
__asm pop ebx
*Length = i;
return retval;
#else // NO X86 optimization , use generic C/C++
while (Buffer[0] == L'\\') {
Buffer++;
}
if (Buffer[0] == L':') {
*Length = 1;
return &(Buffer[1]);
}
for(i = 0; ( Buffer[i] != L'\\' &&
((Buffer[i] != L':') || !i) &&
Buffer[i]); i++);
*Length = i;
return &(Buffer[i]);
#endif // _X86_
} // end UDFDissectName()
BOOLEAN
__fastcall
UDFIsNameValid(
IN PUNICODE_STRING SearchPattern,
OUT BOOLEAN* StreamOpen,
OUT ULONG* SNameIndex
) {
LONG Index, l;
BOOLEAN _StreamOpen = FALSE;
PWCHAR Buffer;
WCHAR c, c0;
if(StreamOpen) (*StreamOpen) = FALSE;
// We can't create nameless file or too long path
if(!(l = SearchPattern->Length/sizeof(WCHAR)) ||
(l>UDF_X_PATH_LEN)) return FALSE;
Buffer = SearchPattern->Buffer;
for(Index = 0; Index<l; Index++, Buffer++) {
// Check for disallowed characters
c = (*Buffer);
if((c == L'*') ||
(c == L'>') ||
(c == L'\"') ||
(c == L'/') ||
(c == L'<') ||
(c == L'|') ||
((c >= 0x0000) && (c <= 0x001f)) ||
(c == L'?')) return FALSE;
// check if this a Stream path (& validate it)
if(!(_StreamOpen) && // sub-streams are not allowed
(Index<(l-1)) && // stream name must be specified
((_StreamOpen) = (c == L':'))) {
if(StreamOpen) (*StreamOpen) = TRUE;
if(SNameIndex) (*SNameIndex) = Index;
}
// According to NT IFS documentation neither SPACE nor DOT can be
// a trailing character
if(Index && (c == L'\\') ) {
if((c0 == L' ') ||
(_StreamOpen) || // stream is not a directory
(c0 == L'.')) return FALSE;
}
c0 = c;
}
// According to NT IFS documentation neither SPACE nor DOT can be
// a trailing character
if((c0 == L' ') ||
(c0 == L'.')) return FALSE;
return TRUE;
} // end UDFIsNameValid()
#ifndef _CONSOLE
/*
Routine Description:
This routine will compare two Unicode strings.
PtrSearchPattern may contain wildcards
Return Value:
BOOLEAN - TRUE if the expressions match, FALSE otherwise.
*/
BOOLEAN
UDFIsNameInExpression(
IN PVCB Vcb,
IN PUNICODE_STRING FileName,
IN PUNICODE_STRING PtrSearchPattern,
OUT PBOOLEAN DosOpen,
IN BOOLEAN IgnoreCase,
IN BOOLEAN ContainsWC,
IN BOOLEAN CanBe8dot3,
IN BOOLEAN KeepIntact // passed to UDFDOSName
)
{
BOOLEAN Match = TRUE;
UNICODE_STRING ShortName;
WCHAR Buffer[13];
if(!PtrSearchPattern) return TRUE;
// we try to open file by LFN by default
if(DosOpen) (*DosOpen) = FALSE;
// If there are wildcards in the expression then we call the
// appropriate FsRtlRoutine.
if(ContainsWC) {
Match = FsRtlIsNameInExpression( PtrSearchPattern, FileName, IgnoreCase, NULL );
// Otherwise do a direct memory comparison for the name string.
} else if (RtlCompareUnicodeString(FileName, PtrSearchPattern, IgnoreCase)) {
Match = FALSE;
}
if(Match) return TRUE;
// check if SFN can match this pattern
if(!CanBe8dot3)
return FALSE;
// try to open by SFN
ShortName.Buffer = (PWCHAR)(&Buffer);
ShortName.MaximumLength = 13*sizeof(WCHAR);
UDFDOSName(Vcb, &ShortName, FileName, KeepIntact);
// PtrSearchPattern is upcased if we are called with IgnoreCase=TRUE
// DOSName is always upcased
// thus, we can use case-sensetive compare here to improve performance
if(ContainsWC) {
Match = FsRtlIsNameInExpression( PtrSearchPattern, &ShortName, FALSE, NULL );
// Otherwise do a direct memory comparison for the name string.
} else if (!RtlCompareUnicodeString(&ShortName, PtrSearchPattern, FALSE)) {
Match = TRUE;
}
if(DosOpen && Match) {
// remember that we've opened file by SFN
(*DosOpen) = TRUE;
}
return Match;
} // end UDFIsNameInExpression()
#endif
BOOLEAN
__fastcall
UDFIsMatchAllMask(
IN PUNICODE_STRING Name,
OUT BOOLEAN* DosOpen
)
{
USHORT i;
PWCHAR Buffer;
if(DosOpen)
*DosOpen = FALSE;
Buffer = Name->Buffer;
if(Name->Length == sizeof(WCHAR)) {
// Win32-style wildcard
if((*Buffer) != L'*')
return FALSE;
return TRUE;
} else
if(Name->Length == sizeof(WCHAR)*(8+1+3)) {
// DOS-style wildcard
for(i=0;i<8;i++,Buffer++) {
if((*Buffer) != DOS_QM)
return FALSE;
}
if((*Buffer) != DOS_DOT)
return FALSE;
Buffer++;
for(i=9;i<12;i++,Buffer++) {
if((*Buffer) != DOS_QM)
return FALSE;
}
if(DosOpen)
*DosOpen = TRUE;
return TRUE;
} else
if(Name->Length == sizeof(WCHAR)*(3)) {
// DOS-style wildcard
if(Buffer[0] != DOS_STAR)
return FALSE;
if(Buffer[1] != DOS_DOT)
return FALSE;
if(Buffer[2] != DOS_STAR)
return FALSE;
if(DosOpen)
*DosOpen = TRUE;
return TRUE;
} else {
return FALSE;
}
} // end UDFIsMatchAllMask()
BOOLEAN
__fastcall
UDFCanNameBeA8dot3(
IN PUNICODE_STRING Name
)
{
if(Name->Length >= 13 * sizeof(WCHAR))
return FALSE;
ULONG i,l;
ULONG dot_pos=0;
ULONG ext_len=0;
PWCHAR buff = Name->Buffer;
l = Name->Length / sizeof(WCHAR);
for(i=0; i<l; i++, buff++) {
if( ((*buff) == L'.') ||
((*buff) == DOS_DOT) ) {
if(dot_pos)
return FALSE;
dot_pos = i+1;
} else
if(dot_pos) {
ext_len++;
if(ext_len > 3)
return FALSE;
} else
if(i >= 8) {
return FALSE;
}
}
return TRUE;
} // end UDFCanNameBeA8dot3()