1 //////////////////////////////////////////////////////////////////// 2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3 // All rights reserved 4 // This file was released under the GPLv2 on June 2015. 5 //////////////////////////////////////////////////////////////////// 6 /* 7 Module: 8 Namesup.cpp 9 10 Abstract: FileName support routines 11 */ 12 13 #include "udffs.h" 14 15 // '\dfdf\aaa\ffg' --> '\aaa\ffg' 16 // '\aaa\ffg' --> '\ffg' 17 PWCHAR 18 __fastcall 19 UDFDissectName( 20 IN PWCHAR Buffer, 21 OUT PUSHORT Length 22 ) 23 { 24 25 USHORT i; 26 27 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 28 29 PWCHAR retval; 30 31 __asm push ebx 32 __asm push ecx 33 34 __asm mov ebx,Buffer 35 __asm xor ecx,ecx 36 Remove_leading_slash: 37 __asm cmp [word ptr ebx],L'\\' 38 __asm jne No_IncPointer 39 __asm add ebx,2 40 __asm jmp Remove_leading_slash 41 No_IncPointer: 42 __asm cmp [word ptr ebx],L':' 43 __asm jne Scan_1 44 __asm add ebx,2 45 __asm inc ecx 46 __asm jmp EO_Dissect 47 Scan_1: 48 __asm mov ax,[word ptr ebx] 49 __asm cmp ax,L'\\' 50 __asm je EO_Dissect 51 __asm or ax,ax 52 __asm jz EO_Dissect 53 __asm cmp ax,L':' 54 __asm jne Cont_scan 55 __asm or ecx,ecx 56 __asm jnz EO_Dissect 57 Cont_scan: 58 __asm inc ecx 59 __asm add ebx,2 60 __asm jmp Scan_1 61 EO_Dissect: 62 __asm mov retval,ebx 63 __asm mov i,cx 64 65 __asm pop ecx 66 __asm pop ebx 67 68 *Length = i; 69 return retval; 70 71 #else // NO X86 optimization , use generic C/C++ 72 73 while (Buffer[0] == L'\\') { 74 Buffer++; 75 } 76 if (Buffer[0] == L':') { 77 *Length = 1; 78 return &(Buffer[1]); 79 } 80 for(i = 0; ( Buffer[i] != L'\\' && 81 ((Buffer[i] != L':') || !i) && 82 Buffer[i]); i++); 83 *Length = i; 84 return &(Buffer[i]); 85 86 #endif // _X86_ 87 88 } // end UDFDissectName() 89 90 BOOLEAN 91 __fastcall 92 UDFIsNameValid( 93 IN PUNICODE_STRING SearchPattern, 94 OUT BOOLEAN* StreamOpen, 95 OUT ULONG* SNameIndex 96 ) { 97 LONG Index, l; 98 BOOLEAN _StreamOpen = FALSE; 99 PWCHAR Buffer; 100 WCHAR c, c0; 101 102 if(StreamOpen) (*StreamOpen) = FALSE; 103 // We can't create nameless file or too long path 104 if(!(l = SearchPattern->Length/sizeof(WCHAR)) || 105 (l>UDF_X_PATH_LEN)) return FALSE; 106 Buffer = SearchPattern->Buffer; 107 for(Index = 0; Index<l; Index++, Buffer++) { 108 // Check for disallowed characters 109 c = (*Buffer); 110 if((c == L'*') || 111 (c == L'>') || 112 (c == L'\"') || 113 (c == L'/') || 114 (c == L'<') || 115 (c == L'|') || 116 ((c >= 0x0000) && (c <= 0x001f)) || 117 (c == L'?')) return FALSE; 118 // check if this a Stream path (& validate it) 119 if(!(_StreamOpen) && // sub-streams are not allowed 120 (Index<(l-1)) && // stream name must be specified 121 ((_StreamOpen) = (c == L':'))) { 122 if(StreamOpen) (*StreamOpen) = TRUE; 123 if(SNameIndex) (*SNameIndex) = Index; 124 } 125 // According to NT IFS documentation neither SPACE nor DOT can be 126 // a trailing character 127 if(Index && (c == L'\\') ) { 128 if((c0 == L' ') || 129 (_StreamOpen) || // stream is not a directory 130 (c0 == L'.')) return FALSE; 131 } 132 c0 = c; 133 } 134 // According to NT IFS documentation neither SPACE nor DOT can be 135 // a trailing character 136 if((c0 == L' ') || 137 (c0 == L'.')) return FALSE; 138 return TRUE; 139 } // end UDFIsNameValid() 140 141 142 #ifndef _CONSOLE 143 /* 144 145 Routine Description: 146 147 This routine will compare two Unicode strings. 148 PtrSearchPattern may contain wildcards 149 150 Return Value: 151 152 BOOLEAN - TRUE if the expressions match, FALSE otherwise. 153 154 */ 155 BOOLEAN 156 UDFIsNameInExpression( 157 IN PVCB Vcb, 158 IN PUNICODE_STRING FileName, 159 IN PUNICODE_STRING PtrSearchPattern, 160 OUT PBOOLEAN DosOpen, 161 IN BOOLEAN IgnoreCase, 162 IN BOOLEAN ContainsWC, 163 IN BOOLEAN CanBe8dot3, 164 IN BOOLEAN KeepIntact // passed to UDFDOSName 165 ) 166 { 167 BOOLEAN Match = TRUE; 168 UNICODE_STRING ShortName; 169 WCHAR Buffer[13]; 170 171 if(!PtrSearchPattern) return TRUE; 172 // we try to open file by LFN by default 173 if(DosOpen) (*DosOpen) = FALSE; 174 // If there are wildcards in the expression then we call the 175 // appropriate FsRtlRoutine. 176 if(ContainsWC) { 177 Match = FsRtlIsNameInExpression( PtrSearchPattern, FileName, IgnoreCase, NULL ); 178 // Otherwise do a direct memory comparison for the name string. 179 } else if (RtlCompareUnicodeString(FileName, PtrSearchPattern, IgnoreCase)) { 180 Match = FALSE; 181 } 182 183 if(Match) return TRUE; 184 185 // check if SFN can match this pattern 186 if(!CanBe8dot3) 187 return FALSE; 188 189 // try to open by SFN 190 ShortName.Buffer = (PWCHAR)(&Buffer); 191 ShortName.MaximumLength = 13*sizeof(WCHAR); 192 UDFDOSName(Vcb, &ShortName, FileName, KeepIntact); 193 194 // PtrSearchPattern is upcased if we are called with IgnoreCase=TRUE 195 // DOSName is always upcased 196 // thus, we can use case-sensetive compare here to improve performance 197 if(ContainsWC) { 198 Match = FsRtlIsNameInExpression( PtrSearchPattern, &ShortName, FALSE, NULL ); 199 // Otherwise do a direct memory comparison for the name string. 200 } else if (!RtlCompareUnicodeString(&ShortName, PtrSearchPattern, FALSE)) { 201 Match = TRUE; 202 } 203 if(DosOpen && Match) { 204 // remember that we've opened file by SFN 205 (*DosOpen) = TRUE; 206 } 207 return Match; 208 } // end UDFIsNameInExpression() 209 210 #endif 211 212 BOOLEAN 213 __fastcall 214 UDFIsMatchAllMask( 215 IN PUNICODE_STRING Name, 216 OUT BOOLEAN* DosOpen 217 ) 218 { 219 USHORT i; 220 PWCHAR Buffer; 221 222 if(DosOpen) 223 *DosOpen = FALSE; 224 Buffer = Name->Buffer; 225 if(Name->Length == sizeof(WCHAR)) { 226 // Win32-style wildcard 227 if((*Buffer) != L'*') 228 return FALSE; 229 return TRUE; 230 } else 231 if(Name->Length == sizeof(WCHAR)*(8+1+3)) { 232 // DOS-style wildcard 233 for(i=0;i<8;i++,Buffer++) { 234 if((*Buffer) != DOS_QM) 235 return FALSE; 236 } 237 if((*Buffer) != DOS_DOT) 238 return FALSE; 239 Buffer++; 240 for(i=9;i<12;i++,Buffer++) { 241 if((*Buffer) != DOS_QM) 242 return FALSE; 243 } 244 if(DosOpen) 245 *DosOpen = TRUE; 246 return TRUE; 247 } else 248 if(Name->Length == sizeof(WCHAR)*(3)) { 249 // DOS-style wildcard 250 if(Buffer[0] != DOS_STAR) 251 return FALSE; 252 if(Buffer[1] != DOS_DOT) 253 return FALSE; 254 if(Buffer[2] != DOS_STAR) 255 return FALSE; 256 if(DosOpen) 257 *DosOpen = TRUE; 258 return TRUE; 259 } else { 260 return FALSE; 261 } 262 } // end UDFIsMatchAllMask() 263 264 BOOLEAN 265 __fastcall 266 UDFCanNameBeA8dot3( 267 IN PUNICODE_STRING Name 268 ) 269 { 270 if(Name->Length >= 13 * sizeof(WCHAR)) 271 return FALSE; 272 273 ULONG i,l; 274 ULONG dot_pos=0; 275 ULONG ext_len=0; 276 PWCHAR buff = Name->Buffer; 277 278 l = Name->Length / sizeof(WCHAR); 279 280 for(i=0; i<l; i++, buff++) { 281 if( ((*buff) == L'.') || 282 ((*buff) == DOS_DOT) ) { 283 if(dot_pos) 284 return FALSE; 285 dot_pos = i+1; 286 } else 287 if(dot_pos) { 288 ext_len++; 289 if(ext_len > 3) 290 return FALSE; 291 } else 292 if(i >= 8) { 293 return FALSE; 294 } 295 } 296 return TRUE; 297 } // end UDFCanNameBeA8dot3() 298