//////////////////////////////////////////////////////////////////// // 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') || (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 3) return FALSE; } else if(i >= 8) { return FALSE; } } return TRUE; } // end UDFCanNameBeA8dot3()